리듀서
액션은 무언가 일어난다는 사실을 기술하지만, 그결과 앱의 상태가 어떻게 바뀌는지는 상관하지 않는다. 이부분은 리듀서가 담당한다. 리듀서는 이전상태와 액션을 받아 다음상태를 반환하는 순수함수 이다.
(prevState, action) => newState
순수함수에서는 아래와 3가지를 절대로 해서는 안된다.
- 인수를 변경(mutate state)
- API호출이나 라우팅등 사이드이팩트
Date.now()
나Math.random()
같이 순수하지 않은(불량하게 값이 매번 다른) 함수 호출하기
리듀서는 반드시 순수해야 하며 인수가 주어지면 다음상태를 계산해서 반환해야한다. 그값은 당연히 예상가능해야하고 예상치 못한일이 일어나면 안된다.(assign메소드는 구현되지 않은 브라우저도 많기 때문에 _.assign()을 사용하면 된다.)
import {ADD_TODO, REMOVE_TODO}'../actions/types'
function reducer (state, {todo}) {
switch (action.type) {
case ADD_TODO :
return Object.assign({}, state, {todo})
case REMOVE_TODO :
return Objevt.assign({}, state, {todo: null})
}
}
예) spread_operator를 사용한 조금 안익숙한 reducer
function calendar (state = initialCalendarState, action) {
const { day, recipe, meal } = action
switch (action.type) {
case ADD_RECIPE :
return {
...state,
[day]: {
...state[day],
[meal]: recipe.label,
}
}
case REMOVE_FROM_CALENDAR :
return {
...state,
[day]: {
...state[day],
[meal]: null,
}
}
default :
return state
}
}
여러개의 리듀서관리 하기
이런식으로 할 수도 있고
export default function todoApp(state, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
};
}
이런식으로 파일을 따로 만들어(index.js) 리듀서들을 가져와 관리 할 수도 있다.
import { combineReducers } from 'redux';
const todoApp = combineReducers({
visibilityFilter,
todos
});
export default todoApp;
이 두가지는 완전히 같은 의미의 코드이다.