3-3. 리덕스에서 사용하기

자, 리덕스에서 Immutable 을 사용하는 방법을 알아보겠습니다.

기존에 만들었던 프로젝트에서 우리가 배웠던것들을 적용해볼게요.

설치

우선, immutable 을 설치하세요.

yarn add immutable

리듀서 수정

이제 리듀서에서 immutable 을 불러오고 사용을 해보겠습니다.

src/reducers/index.js

우선 코드의 상단에서 Map 과 List 를 불러오세요.

import { Map, List } from 'immutable';

그 다음, initialState 를 Map 과 List 를 사용해서 만드세요.

const initialState = Map({
    counters: List([
        Map({
            color: 'black',
            number: 0
        })
    ])
})

{ } 은 Map 으로, [ ] 은 List 로 하시면 됩니다.

자, 이제 리듀서를 전체적으로 처음부터 작성할것입니다. 걱정하지마세요, immutable과 함께라면 금방 합니다.

// 리듀서 함수를 정의합니다. 
function counter(state = initialState, action) {
    const counters = state.get('counters');

    switch(action.type) {
        // 카운터를 새로 추가합니다
        case types.CREATE:
            return state.set('counters', counters.push(Map({
                color: action.color,
                number: 0
            })))
        // slice 를 이용하여 맨 마지막 카운터를 제외시킵니다
        case types.REMOVE:
            return state.set('counters', counters.pop());

        // action.index 번째 카운터의 number 에 1 을 더합니다.
        case types.INCREMENT:
            return state.set('counters', counters.update(
                action.index, 
                (counter) => counter.set('number', counter.get('number') + 1))
            );

        // action.index 번째 카운터의 number 에 1 을 뺍니다
        case types.DECREMENT:
            return state.set('counters', counters.update(
                action.index, 
                (counter) => counter.set('number', counter.get('number') - 1))
            );

        // action.index 번째 카운터의 색상을 변경합니다
        case types.SET_COLOR:
            return state.set('counters', counters.update(
                action.index, 
                (counter) => counter.set('color', action.color))
            );
        default:
            return state;
    }
};

어때요? 기존 코드보다 훨씬 간결해지고, 읽기도 쉬워졌지요?

그럼 전체코드를 확인해볼까요?

import { Map, List } from 'immutable';
import * as types from '../actions/ActionTypes';

// 초기 상태를 정의합니다.
const initialState = Map({
    counters: List([
        Map({
            color: 'black',
            number: 0
        })
    ])
})

// 리듀서 함수를 정의합니다. 
function counter(state = initialState, action) {
    const counters = state.get('counters');

    switch(action.type) {
        // 카운터를 새로 추가합니다
        case types.CREATE:
            return state.set('counters', counters.push(Map({
                color: action.color,
                number: 0
            })))
        // pop 을 사용하여 맨 마지막 카운터를 제거합니
        case types.REMOVE:
            return state.set('counters', counters.pop());

        // action.index 번째 카운터의 number 에 1 을 더합니다.
        case types.INCREMENT:
            return state.set('counters', counters.update(
                action.index, 
                (counter) => counter.set('number', counter.get('number') + 1))
            );

        // action.index 번째 카운터의 number 에 1 을 뺍니다
        case types.DECREMENT:
            return state.set('counters', counters.update(
                action.index, 
                (counter) => counter.set('number', counter.get('number') - 1))
            );

        // action.index 번째 카운터의 색상을 변경합니다
        case types.SET_COLOR:
            return state.set('counters', counters.update(
                action.index, 
                (counter) => counter.set('color', action.color))
            );
        default:
            return state;
    }
};

export default counter;

컴포넌트 수정

리듀서에서 이제 immutable 을 사용하니, 컴포넌트에서도 이를 반영시켜주어야겠죠?

src/containers/CounterListContainer.js

CounterListContainer 컴포넌트의 mapStateToProps 에서, state.counters 대신 state.get('counters')로 수정하세요.

// store 안의 state 값을 props 로 연결해줍니다.
const mapStateToProps = (state) => ({
    counters: state.get('counters')
});

src/components/CounterList.js

다음, CounterList 컴포넌트에서 배열을 매핑하는 과정에서 {...counter}{...counter.toJS()}로 수정하고, propType 도 PropTypes.instanceOf(List) 로 수정하세요.

import React from 'react';
import Counter from './Counter';
import PropTypes from 'prop-types';
import { List } from 'immutable';

import './CounterList.css';

const CounterList = ({counters, onIncrement, onDecrement, onSetColor}) => {

    const counterList = counters.map(
        (counter, i) => (
            <Counter 
                key={i}
                index={i}
                {...counter.toJS()}
                onIncrement={onIncrement}
                onDecrement={onDecrement}
                onSetColor={onSetColor}
            />
        )
    );

    return (
        <div className="CounterList">
            {counterList}
        </div>
    );
};

CounterList.propTypes = {
    counters: PropTypes.instanceOf(List),
    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;

이제 다 끝났습니다! 카운터가 제대로 작동하는지 확인해보세요.

여기까지의 코드는 GitHub 에서 확인 하실 수 있습니다.

results matching ""

    No results matching ""