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로 전달받습니다.

countersCounter 컴포넌트 배열로 로 변환하는 과정에선, 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;

자, 프리젠테이셔널 컴포넌트들이 모두 완성되었습니다. 컴포넌트가 어떻게보여줄지 준비가 다 끝났으니, 데이터를 어떻게 넣어줄지 고민을 해봅시다.

results matching ""

    No results matching ""