2-3. Reducers 고치기
이제 리듀서를 고칠 차례입니다.
1장에서 만들었던 리듀서들과 작동방식이 다르므로, reducers 디렉토리 안에 있는 기존에 만들었던 color.js
, number.js
를 삭제하고, index.js
파일은 내용을 비우고 새로 작성하세요.
우선 초기상태부터 정의를 해보겠습니다.
src/reducers/index.js
import * as types from '../actions/ActionTypes';
// 초기 상태를 정의합니다.
const initialState = {
counters: [
{
color: 'black',
number: 0
}
]
}
상태안에 counters 라는 배열을 만들고, 그 안에 color
, number
값을 지니고있는 객체를 만들어서 넣어줬습니다.
리듀서 함수에서 추가 / 삭제 구현
src/reducers/index.js
import * as types from '../actions/ActionTypes';
// 초기 상태를 정의합니다.
const initialState = {
counters: [
{
color: 'black',
number: 0
}
]
}
// 리듀서 함수를 정의합니다.
function counter(state = initialState, action) {
// 레퍼런스 생성
const { counters } = state;
switch(action.type) {
// 카운터를 새로 추가합니다
case types.CREATE:
return {
counters: [
...counters,
{
color: action.color,
number: 0
}
]
};
// slice 를 이용하여 맨 마지막 카운터를 제외시킵니다
case types.REMOVE:
return {
counters: counters.slice(0, counters.length - 1)
};
default:
return state;
}
};
export default counter
컴포넌트의 state 안에있는 배열을 다룰때와 동일하게, 기존 배열에 직접 push()
혹은 pop()
을 하면 안돼고, ...
(spread 문법)을 사용하거나, .slice()
함수를 사용하여 배열을 잘라 새로 생성을 해야 합니다.
이 과정에서, state.counters
를 자주 사용해야하므로, 이를 줄여서 사용하여 코드를 줄이기 위해 상단에 레퍼런스를 만들어서 사용하면 코드가 더 깔끔해집니다.
앞으로 계속해서 구현 할 숫자 더하기, 빼기, 그리고 색상변경을 위한 부분들은, 코드가 조금 복잡해 보일수도 있지만, 위 코드의 똑같은 원리입니다.
리듀서 함수에 더하기, 빼기, 색상변경 구현
src/reducers/index.js
import * as types from '../actions/ActionTypes';
// 초기 상태를 정의합니다.
const initialState = {
counters: [
{
color: 'black',
number: 0
}
]
}
// 리듀서 함수를 정의합니다.
function counter(state = initialState, action) {
// 레퍼런스 생성
const { counters } = state;
switch(action.type) {
// 카운터를 새로 추가합니다
case types.CREATE:
return {
counters: [
...counters,
{
color: action.color,
number: 0
}
]
};
// slice 를 이용하여 맨 마지막 카운터를 제외시킵니다
case types.REMOVE:
return {
counters: counters.slice(0, counters.length - 1)
};
// action.index 번째 카운터의 number 에 1 을 더합니다.
case types.INCREMENT:
return {
counters: [
...counters.slice(0, action.index),
{
...counters[action.index],
number: counters[action.index].number + 1
},
...counters.slice(action.index + 1, counters.length)
]
};
// action.index 번째 카운터의 number 에 1 을 뺍니다
case types.DECREMENT:
return {
counters: [
...counters.slice(0, action.index),
{
...counters[action.index],
number: counters[action.index].number - 1
},
...counters.slice(action.index + 1, counters.length)
]
};
// action.index 번째 카운터의 색상을 변경합니다
case types.SET_COLOR:
return {
counters: [
...counters.slice(0, action.index),
{
...counters[action.index],
color: action.color
},
...counters.slice(action.index + 1, counters.length)
]
};
default:
return state;
}
};
export default counter;
INCREMENT
한개만 이해하고나면, 나머지는 복사 붙이기하여 손쉽게 구현 할 수 있습니다.
한번 주석과 함께 살펴볼까요?
case types.INCREMENT:
return {
counters: [
...counters.slice(0, action.index), // 0 ~ action.index 사이의 아이템들을 잘라와서 이 자리에 넣는다
{
...counters[action.index], // 기존 값은 유지하면서
number: counters[action.index].number + 1 // number 값을 덮어쓴다
},
...counters.slice(action.index + 1, counters.length) // action.index + 1 ~ 마지막까지 잘라온
]
};
DECREMENT
, SET_COLOR
도 똑같은 원리로 구현하면 됩니다.
배열을 바꾸거나, 이런 작업을 하는게, 그렇게 어려운 작업은 아니지만 간단한 작업 하나 하자고 코드를 필요 이상으로 많이 쓴다는 기분이 드는것은 사실입니다. 이번 멀티 카운터를 만들고 나서 immutable
이란 라이브러리를 사용해볼건데요. 이 라이브러리를 사용하면 위와 비슷한 작업을 더욱 가독성 높고 짧게 구현 할 수 있게 해줍니다.
이렇게 리듀서를 수정하고 나면, 기존 카운터가 제대로 작동하지 않을텐데, 이는 우리가 곧 고쳐나갈 것이니 당황하지 마세요.