1. 리덕스를 더 편하게 사용하는 방법
액션 생성 함수,리듀서 작성 시에 사용한 react-actions 라이브러리와 Immer 라이브러리
이렇게 3가지를 사용하면 리덕스를 훨신 편하게 사용할 수 있습니다.
1.1 redux-actions
redux-actions 라는 라이브러리를 사용하면 액션 생성 함수를 더 짧은 코드로 작성할 수 있습니다.
그리고 리듀서를 작성할 떄 switch/case 문이 아닌 handleActions 라는 함수를 사용하여 각
액션을 업데이트 하도록 함수를 작성할 수 있습니다.
yarn add redux-actions
먼저 위의 명령어로 라이브러리를 추가 설치합니다.
1.2 counter 모듈 적용하기
counter 모듈에 작성했던 액션 생성함수를 createAction이란 함수를 사용하여 바꿔 줍니다.
- modules/counter.js
import { createAction } from "redux-actions";
// 액션의 타입 정의
const INCREASE = 'counter/INCREASE';
const DECREASE = "counter/DECREASE";
// 액션 생성함수 생성
export const increase = createAction(INCREASE);
export const decrease = createAction(DECREASE);
(...)
createAction 함수로 매번 객체를 만들어 주지 않고 간단하게 액션 함수를 사용할 수 있습니다.
import { createAction, handleActions } from "redux-actions";
// 액션의 타입 정의
const INCREASE = 'counter/INCREASE';
const DECREASE = "counter/DECREASE";
// 액션 생성함수 생성
export const increase = createAction(INCREASE);
export const decrease = createAction(INCREASE);
// 초기값 설정
const initialState = {
number: 0
}
// 리듀서 함수정의
const counter = handleActions(
{
[INCREASE]: (state, action) => ({ number: state.number + 1}),
[DECREASE]: (state, action) => ({ number: state.number - 1}),
},
initialState,
)
export default counter;
handleActions 함수의 첫 번째 파라미터에는 액션에 대한 업데이트 함수를 넣어주고, 두 번째 파라미터에는 초기에 가지고 있는 상태 값을 넣어줍니다.
switch case 문 사용시 보다 코드도 짧아지고 가독성도 좋아진 걸 볼 수 있습니다.
1.3 todos 모듈 적용하기
같은 작업을 todos 모듈에도 적용해 줍시다.
- modules/todos.js
import { createAction } from "redux-actions";
const CHANGE_INPUT = "todos/CHANGE_INPUT"; // 인풋 값 변경
const INSERT = "todos/INSERT"; // 새로운 todo 등록
const TOGGLE = "todos/TOGGLE"; // todo 체크박스 체크/체크 해제
const REMOVE = "todos/REMOVE"; // todo 삭제
export const changeInput = createAction(CHANGE_INPUT, input => input);
let id = 3; // insert 호출시 1씩 증가
export const insert = createAction(INSERT, text => ({
id: id++,
text,
done: false,
}));
export const toggle = createAction(TOGGLE, (id) => id);
export const remove = createAction(REMOVE, (id) => id);
(...)
- insert: todo 객체를 액션 객체 안에 넣어주어야 해서 두 번째 파라미터에 text를 넣고 todo 객체가 반환되는 함수를 추가
- 나머지의 경우 text -> text, id => id 형태로 파라미터를 그대로 반환하도록 함수를 추가
이제는 handleActions로 리듀서를 수정해 보겠습니다.
import { createAction, handleActions } from "redux-actions";
const CHANGE_INPUT = "todos/CHANGE_INPUT"; // 인풋 값 변경
const INSERT = "todos/INSERT"; // 새로운 todo 등록
const TOGGLE = "todos/TOGGLE"; // todo 체크박스 체크/체크 해제
const REMOVE = "todos/REMOVE"; // todo 삭제
export const changeInput = createAction(CHANGE_INPUT, input => input);
let id = 3; // insert 호출시 1씩 증가
export const insert = createAction(INSERT, text => ({
id: id++,
text,
done: false,
}));
export const toggle = createAction(TOGGLE, (id) => id);
export const remove = createAction(REMOVE, (id) => id);
const initalState = {
input: '',
todos: [
{
id: 1,
text: '리덕스 기초 학습',
done: true
},
{
id: 2,
text: '리엑트와 리덕스 사용',
done: false
}
]
};
const todos = handleActions({
[CHANGE_INPUT]: (state, { payload: input }) => ({ ...state, input }),
[INSERT]: (state, { payload: todo }) => ({
...state,
todos: state.todos.concat(todo),
}),
[TOGGLE]: (state, { payload: id }) => ({
...state,
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, done: !todo.done } : todo,
),
}),
[REMOVE]: (state, {payload: id }) => ({
...state,
todos: state.todos.filter(todo => todo.id !== id),
}),
},
initalState,
);
export default todos;
이전보다 코드 가독성이 더 좋아진걸 볼 수 있습니다.
1.4 immer
리듀서에서 상태를 업데이트 할 떄 불변성을 지켜야 할 필요가 있어서 이전에는 spread 연산자와 배열의 내장함수를 사용 했습니다.
그렇지만 모듈의 상태(형태)가 더 복잡해질수록 불변성을 유지하기가 어렵습니다.
따라서 모듈의 상태를 설계할 떄 객체를 너무 깊이있게 하지 않도록 할 필요가 있습니다.
객체의 구조가 복잡해지거나 객체로 이루어진 배열을 다룰경우 immer를 사용하면 훨신 쉽게 상태를 관리할 수 있습니다.
yarn add immer
먼저 immer 라이브러리를 설치합니다.
counter 모듈같이 간단한 리듀서에 immer을 적용하면 코드가 더 깊어질 수 있습니다.
따라서 todos 모듈에 적용해 보겠습니다.
- modules/todos.js
import { createAction, handleActions } from "redux-actions";
import produce from "immer";
(...)
const todos = handleActions({
[CHANGE_INPUT]: (state, { payload: input }) =>
produce(state, draft => {
draft.input = input;
}),
[INSERT]: (state, { payload: todo }) =>
produce(state, draft => {
draft.todos.push(todo);
}),
[TOGGLE]: (state, { payload: id }) =>
produce(state, draft => {
const todo = draft.todos.findIndex(todo => todo.id === id);
todo.done = !todo.done;
}),
[REMOVE]: (state, {payload: id }) =>
produce(state, draft => {
const index = draft.todos.findIndex(todo => todo.id === id);
draft.todos.splice(index, 1)
}),
},
initalState,
);
export default todos;
immer을 사용한다고 해서 모든 업데이트 함수에 적용할 필요는 없습니다.
일반 자바스크립트로 처리하는것이 더 편할 때는 immer을 사용할 필요 없습니다.
예를 들어 TOGGLE을 제외한 업데이트 함수는 immer을 쓰지 않을 경우 코드가 더 간결해지기 때문에 사용하지 않아도 무방합니다.
'프론트엔드 > React' 카테고리의 다른 글
[프론트엔드] 리덕스 미들웨어를 통한 비동기 작업 관리[1] (0) | 2022.04.12 |
---|---|
[프론트엔드] 리덕스를 사용하여 리액트 어플리케이션 상태 관리하기[9] (0) | 2022.04.11 |
[프론트엔드] 리덕스를 사용하여 리액트 어플리케이션 상태 관리하기[7] (0) | 2022.04.10 |
[프론트엔드] 리덕스를 사용하여 리액트 어플리케이션 상태 관리하기[6] (0) | 2022.04.10 |
[프론트엔드] 리덕스를 사용하여 리액트 어플리케이션 상태 관리하기[5] (0) | 2022.04.10 |