2-4. 프리젠테이셔널 컴포넌트 만들기
이번 섹션에서는, 여러개의 카운터를 다루기 위해서, 카운터 생성/제거를 담당할 Buttons
컴포넌트와 여러개의 카운터를 렌더링해줄 CounterList
를 만들어보겠습니다.
생성/제거버튼 - Buttons 컴포넌트 만들기
이 컴포넌트는 두개의 버튼을 내장하고 있으며, 새 카운터를 생성하는 onCreate
함수, 그리고 맨 마지막 카운터를 제거시킬 onRemove
함수를 props 로 전달받습니다.
src/components/Buttons.js
import React from 'react';
import PropTypes from 'prop-types';
import './Buttons.css';
const Buttons = ({onCreate, onRemove}) => {
return (
<div className="Buttons">
<div className="btn add" onClick={onCreate}>
생성
</div>
<div className="btn remove" onClick={onRemove}>
제거
</div>
</div>
);
};
Buttons.propTypes = {
onCreate: PropTypes.func,
onRemove: PropTypes.func
};
Buttons.defaultProps = {
onCreate: () => console.warn('onCreate not defined'),
onRemove: () => console.warn('onRemove not defined')
};
export default Buttons;
src/components/Button.css
.Buttons {
display: flex;
}
.Buttons .btn {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
height: 3rem;
color: white;
font-size: 1.5rem;
cursor: pointer;
}
.Buttons .add {
background: #37b24d;
}
.Buttons .add:hover {
background: #40c057;
}
.Buttons .remove {
background: #f03e3e;
}
.Buttons .remove:hover {
background: #fa5252;
}
여러 카운터를 렌더링 - CounterList 컴포넌트 만들기
이제 여러 카운터들을 렌더링해줄 CounterList
컴포넌트를 만들어보겠습니다. 이 컴포넌트는 카운터 객체들의 배열 counters
와, 카운터를 조작하는 onIncrement
, onDecrement
, onSetColor
함수를 props로 전달받습니다.
counters
를 Counter
컴포넌트 배열로 로 변환하는 과정에선, key 를 배열의 index 로 설정하고, index 값도 컴포넌트에 props로 전달을 해줍니다. 그리고, color
값과 number
값을 각각 설정하는 대신에, {...counter}
으로 객체를 풀어서 한꺼번에 전달해줄수도 있습니다.
src/components/CounterList.js
import React from 'react';
import Counter from './Counter';
import PropTypes from 'prop-types';
import './CounterList.css';
const CounterList = ({counters, onIncrement, onDecrement, onSetColor}) => {
const counterList = counters.map(
(counter, i) => (
<Counter
key={i}
index={i}
{...counter}
onIncrement={onIncrement}
onDecrement={onDecrement}
onSetColor={onSetColor}
/>
)
);
return (
<div className="CounterList">
{counterList}
</div>
);
};
CounterList.propTypes = {
counters: PropTypes.arrayOf(PropTypes.shape({
color: PropTypes.string,
number: PropTypes.number
})),
onIncrement: PropTypes.func,
onDecrement: PropTypes.func,
onSetColor: PropTypes.func
};
CounterList.defaultProps = {
counters: [],
onIncrement: () => console.warn('onIncrement not defined'),
onDecrement: () => console.warn('onDecrement not defined'),
onSetColor: () => console.warn('onSetColor not defined')
}
export default CounterList;
src/components/CounterList.css
.CounterList {
margin-top: 2rem;
display: flex;
justify-content: center;
flex-wrap: wrap;
}
Counter 컴포넌트 수정하기
프로젝트의 작동방식이 바뀌었으니, Counter
컴포넌트를 수정해주겠습니다. 방금 CounterList
에서 전달한 index
를 각 이벤트가 실행 될 때 함수의 파라미터로 넣어서 실행하게 해주면 됩니다.
src/components/Counter.js
import React from 'react';
import PropTypes from 'prop-types';
import './Counter.css';
const Counter = ({number, color, index, onIncrement, onDecrement, onSetColor}) => {
return (
<div
className="Counter"
onClick={() => onIncrement(index)}
onContextMenu={
(e) => {
e.preventDefault();
onDecrement(index);
}
}
onDoubleClick={() => onSetColor(index)}
style={{backgroundColor: color}}>
{number}
</div>
);
};
Counter.propTypes = {
index: PropTypes.number,
number: PropTypes.number,
color: PropTypes.string,
onIncrement: PropTypes.func,
onDecrement: PropTypes.func,
onSetColor: PropTypes.func
};
Counter.defaultProps = {
index: 0,
number: 0,
color: 'black',
onIncrement: () => console.warn('onIncrement not defined'),
onDecrement: () => console.warn('onDecrement not defined'),
onSetColor: () => console.warn('onSetColor not defined')
};
export default Counter;
자, 프리젠테이셔널 컴포넌트들이 모두 완성되었습니다. 컴포넌트가 어떻게보여줄지 준비가 다 끝났으니, 데이터를 어떻게 넣어줄지 고민을 해봅시다.