리덕스 모듈
- 리덕스 모듈이란?
- 액션 타입(Actions), 액션 생성 함수(Action Creators), 리듀서(Reducer)가 모두 들어있는 자바스크립트 파일을 의미함.
- 이렇게 하나의 파일에 작성하는 것을 덕스(Ducks) 패턴이라고 함.
- 리덕스 모듈에서 리듀서는 default export하고, 액션 생성 함수는 그냥 export함.
"덕스 패턴"이 뭐고 이걸 쓰면 뭐가 좋은걸까?
- 덕스 패턴은 Erik Rasmussen님이 리덕스 사용 방법과 관련하여 제안한 패턴이다. (참고)
- 액션 타입, 액션 생성 함수, 리듀서를 각각 별도의 파일(심지어는 별도의 폴더)에 분리하여 작성하기 보다는, 그 셋을 하나의 모듈처럼 한 파일 안에 작성하자는 제안이다.
- 사실 나는 학원에서 리덕스를 처음 배울 때부터 덕스 패턴으로 작성하는 방식으로 배워서, 이게 덕스 패턴인지도 모르고 그냥 그렇게 작성하는 게 관례(?)인 줄 알고 썼었다.
- 만약 덕스 패턴에 따라 리덕스를 사용하지 않았더라면, 스토어를 만드는 과정이 약간 더 정신없게 느껴지지 않았을까.
- 이렇게 리덕스를 모듈화를 하는 것의 이점은 코드를 작성하는 이도 왔다갔다 하지 않고 하나의 파일 안에서 "1. 액션 타입~ 2. 액션 생성 함수~ 3. 리듀서~" 이런 식으로 순서대로 작성하기만 하면 되니 코드 작성하기가 좀 더 용이할테고, 다른 사람들이 보기에도 코드가 깔끔 명료하고 가독성이 좋다는 것 정도인 것 같다.
- 덕스 패턴의 규칙은 아래와 같다.
- MUST export default a function called reducer()
반드시 리듀서 함수를 default export해야 한다. - MUST export its action creators as functions
반드시 액션 생성 함수를 export해야 한다. - MUST have action types in the form npm-module-or-app/reducer/ACTION_TYPE
반드시 접두사를 붙인 형태로 액션 타입을 정의해야 한다. (아래 예제 코드 참고) - MAY export its action types as UPPER_SNAKE_CASE, if an external reducer needs to listen for them, or if it is a published reusable library
(필수는 아닌데) 외부 리듀서가 모듈 내 액션 타입을 바라보고 있거나, 모듈이 재사용 가능한 라이브러리로 쓰이는 것이라면 액션 타입을 UPPER_SNAKE_CASE 형태로 이름 짓고 export 하면 된다.
- MUST export default a function called reducer()
예제
- src 디렉토리 하위에 modules 디렉토리를 만들고, counter 모듈과 todos 모듈을 만들어보자.
- counter 모듈(src/modules/counter.js)
/* ----------------- 액션 타입 ------------------ */ const SET_DIFF = 'counter/SET_DIFF'; // 얼마만큼 더하거나 뺄지 const INCREASE = 'counter/INCREASE'; const DECREASE = 'counter/DECREASE'; // 덕스 패턴에서는 액션 타입을 정의할 때 이와 같이 접두사를 붙임. // 다른 모듈과 이름이 중복되지 않게 하기 위함. /* ----------------- 액션 생성 함수 ------------------ */ export const setDiff = diff => ({ type: SET_DIFF, diff }); export const increase = () => ({ type: INCREASE }); export const decrease = () => ({ type: DECREASE }); /* ----------------- 모듈의 초기 상태 ------------------ */ const initialState = { number: 0, diff: 1, }; /* ----------------- 리듀서 ------------------ */ export default function counter(state = initialState, action) { switch (action.type) { case SET_DIFF: return { ...state, diff: action.diff, }; case INCREASE: return { ...state, number: state.number + state.diff, }; case DECREASE: return { ...state, number: state.number - state.diff, }; default: return state; } }
- todos 모듈(src/modules/todos.js)
/* ----------------- 액션 타입 ------------------ */ const ADD_TODO = 'todos/ADD_TODO'; const TOGGLE_TODO = 'todos/TOGGLE_TODO'; /* ----------------- 액션 생성 함수 ------------------ */ export const addTodo = (id, text) => ({ type: ADD_TODO, todo: { id, text, done: false, }, }); export const toggleTodo = id => ({ type: TOGGLE_TODO, id, }); /* ----------------- 모듈의 초기 상태 ------------------ */ const initialState = []; // todo list // 아래와 같은 객체가 상태(배열)에 추가될 예정 /** { id: 1, text: '청소하기', done: false, } */ /* ----------------- 리듀서 ------------------ */ export default function todos(state = initialState, action) { switch (action.type) { case ADD_TODO: return state.concat(action.todo); case TOGGLE_TODO: return state.map(todo => todo.id === action.id ? { ...todo, done: !todo.done } : todo ); default: return state; } }
- counter 모듈(src/modules/counter.js)
- 앞서 만든 두 모듈을 하나로 합쳐서 root reducer 만들기
- modules 디렉토리에 index.js 파일 생성 후 아래와 같이 작성
import { combineReducers } from 'redux'; import counter from './counter'; import todos from './todos'; const rootReducer = combineReducers({ counter, todos, }); export default rootReducer;
- modules 디렉토리에 index.js 파일 생성 후 아래와 같이 작성
- 리액트 프로젝트에 리덕스 적용하기
- 리액트 프로젝트에 리덕스를 적용하려면 redux와 react-redux를 설치해야 함.
*참고로 TypeScript를 사용하는 경우 react-redux 타입은 이미 react-redux 패키지에 포함이 되어 있지만, 수동으로 설치를 해야 할 필요가 있다면 아래와 같이 타입을 추가로 설치해주면 됨.# If you use npm: npm install redux react-redux # Or if you use Yarn: yarn add redux react-redux
npm install @types/react-redux
- 설치가 완료되었다면, src/index.js로 가서 Provider, createStore, rootReducer를 불러온다.
이제, 스토어에서 관리되고 있는 애플리케이션 상태를 getStore()로 조회해보자.import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; // 리덕스 적용하기 import { Provider } from 'react-redux'; import { createStore } from 'redux'; import rootReducer from './modules'; // 스토어 생성 const store = createStore(rootReducer); ReactDOM.render( // App을 Provider로 감싸주면 적용 완료! <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); reportWebVitals();
- 리액트 프로젝트에 리덕스를 적용하려면 redux와 react-redux를 설치해야 함.
참고
- 벨로퍼트와 함께하는 모던 리액트 : Redux
- https://github.com/erikras/ducks-modular-redux
- https://medium.com/@matthew.holman/what-is-redux-ducks-46bcb1ad04b7
'dev-log > Front-End' 카테고리의 다른 글
Safari에만 적용되는 코드를 짜고 싶다면? (0) | 2021.10.06 |
---|---|
[Next.js] Next.js에서 CSS 사용하기 (0) | 2021.10.03 |
[React] 리액트 상태 관리의 과거, 현재, 그리고 미래 (0) | 2021.09.29 |
[라이브러리] Chart.js 시작하기 (2) | 2021.08.21 |
React Query (0) | 2021.05.28 |