Todo list 예제를 통한 redux학습하기(6)

오늘은 todo list에 filtering기능을 추가함으로써 기본적인 todo 추가, 완료, 필터링 기능을 완성해볼 것이다.

이전까지는 index.js 하나로 구성되어있던 reducer를 todo와 filter 두 가지로 분리하였고, 이를 redux의 combineReducer()로 통합시켰다.

또한 todos만 관리하고 있던 state에 filter를 추가하여 현재 필터의 상태를 관리하게 했다. filter state는 세 가지 타입이 있는데, 모든 todo의 목록을 보여주는 ‘ALL’과 완료한 todo만 보여주는 ‘COMPLTED’, 완료되지 않은 todos만을 보여주는 ‘NOT_COMPLETED’이다.

// actions/index.js...export const CHANGE_FILTER = 'CHANGE_FILTER';
...
export function changeFilter(filter) {
return { type: CHANGE_FILTER, filter };
}
...

action에는 필터를 변경한다는 의미의 ‘CHANGE_FILTER’ 타입과 어떤 filter로 업데이트되는지 정보를 포함한 changeFilter action을 새로 추가했다.

presentation component인 Filter.js는 filterTypes 중에 현재 state와 일치하는 요소는 활성화시키고, 전체 목록을 list로 만들어준다. ‘nav’나 ‘nav-link’등 className은 이전 포스팅과 마찬가지로 bootstrap을 통해 미관적으로 개선하기 위한 요소이니 꼭 필요한 것은 아니다.

Filter에 state update function과 dispatch function을 전달해 줄 FilterContainer는 mapStateToProps에서 filter의 새로운 상태를 받아 state를 갱신해 준다. mapDispatchToProps에서는 filter를 클릭할 시 클릭 된 filter로 changeFilter action을 만들어 dispatch시켜준다.

// containers/VisibleTodoList.js
...
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case filterTypes.ALL:
return todos;
case filterTypes.COMPLETED:
return todos.filter(todo => {
return todo.completed === true;
});
case filterTypes.NOT_COMPLETED:
return todos.filter(todo => {
return todo.completed === false;
});
default:
return todos;
}
};

const mapStateToProps = state => {
return {
todos: getVisibleTodos(state.todos, state.filter)
}
};
...

선택한 필터에 따라 todo list view를 변경하기 위해서는 VisibleTodoList에도 약간의 수정이 필요하다. getVisibleTodos에서 현재 filter의 상태를 전달받아 mapStateToProps에서 적절한 todos만을 필터링해 리턴해준다. getBisibleTodos에서 filter를 전달받기 위해 이를 호출하는 mapStateToProps에서는 state.filter를 파라미터로 함께 넘겨준다.

reducer에서는 앞서 언급했듯이 filter와 todos를 분리해서 index에서 이를 합쳐줄 것이다.

reducers/filter.js
import { CHANGE_FILTER } from "../acitons";

export default function filter(state = 'ALL', action) {
switch (action.type) {
case CHANGE_FILTER:
return action.filter;
default:
return state;
}
}

filter.js는 action.type이 CHANGE_FILTER이면 action의 filter를 반환해준다.

//reducers/index.js
import { combineReducers } from 'redux';

import todos from './todos';
import filter from './filter';

const todoApp = combineReducers({
todos,
filter
});

export default todoApp;

todos역시 같은 방식으로 todos.js로 분리시킨 후 index.js에서 todos와 filter를 전달받아 combineReducers로 합쳐주면 완성된다!

Image for post
Image for post

woohyun

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store