본문 바로가기

Redux

[Redux] 3. 리덕스 모듈 만들기

리액트 프로젝트에 리덕스를 적용하기 위해서 리덕스 모듈을 만들어보자!

리덕스 모듈은 다음과 같은 항목들이 모두 들어있는 자바스크립트 파일이다.

1. 액션 타입
2. 액션 생성함수
3. 리듀서

위 항목들을 각각 다른 파일에 저장할 수도 있다.

리덕스 공식 GitHub 레퍼지토리에 등록되어있는 예제 프로젝트를 보면 아래와 같이 코드가 분리되어 있다.

  • actions
    • index.js
  • reducers
    • todos.js
    • visibilityFilter.js
    • index.js

구조를 보면 액션과 리듀서가 다른 파일에 정의되어 있는 것을 알 수 있다.

하지만, 코드들이 꼭 분리되어야 하는 것은 아니다. 코드들이 다른 디렉터리에, 다른 파일에 분리되어 있으면

개발할 때 꽤 불편할 수도 있다. 그래서 우리는 리듀서와 액션 관련 코드들을 하나의 파일에 몰아서 작성할 것이고 이런 패턴을 Ducks 패턴이라고 부른다.

Ducks 패턴: 기능중심으로 파일을 나누는 패턴을 말한다.
💡 액션 타입과 액션 생성자 함수, 리듀서 등을 하나의 파일에서 관리한다.

❗ 주의할 점
1. 리듀서 함수는 export default로 정의해야 한다.
2. 액션 함수는 export로 정의해야 한다.
3. 액션타입을 정의할 때 reducer/ACTION_TYPE 형태로 적어줘야 한다.

counter 모듈 만들기

기본적인 사항들을 모두 알았으니 counter 모듈을 만들어보자

src 디렉터리에 modules 디렉터리를 생성하고, 내부에 counter.js 파일을 생성하여 다음과 같이 코드를 작성한다.

modules/counter.js

먼저, 액션 타입을 미리 선언해주자

const SET_DIFF = 'counter/SET_DIFF';
const INCREASE = 'counter/INCREASE';
const DECREASE = 'counter/DECREASE';
💡 Ducks 패턴을 사용할 땐 액션의 이름에 접두사를 넣어줘 다른 모듈과 액션 이름이 중복되는 것을 방지할 수 있다.

 

액션 생성함수를 만들고 export 키워드를 사용해서 내보내준다.

여기서는 화살표 함수가 간편해서 화살표 함수를 사용했지만 일반 함수로 작성해도 상관없다. 

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 키워드를 사용해서 내보내준다.

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 모듈 만들기

내친김에 todos 모듈까지 만들어보자.

counter 모듈과 마찬가지로 modules 디렉터리에 todos.js 파일을 생성하고 다음과 같이 코드를 작성한다.

modules/todos.js

액션 타입 먼저 선언

const ADD_TODO = 'todos/ADD_TODO';
const TOGGLE_TODO = 'todos/TOGGLE_TODO';

 

액션 생성함수 선언

여기서 nextId는 todo 데이터에서 사용할 고유 id 변수이다.

let nextId = 1;

export const addTodo = text => ({
    type: ADD_TODO,
    todo: {
        id: nextId++,
        text
    }
});

export const toggleTodo = id => ({
    type: TOGGLE_TODO,
    id
});

 

초기 상태 선언

const initialState = [];

 

리듀서 함수를 선언하고 export default 키워드를 사용해서 내보내준다.

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;
    }
}

루트 리듀서 만들기

현재까지 countertodos 모듈 두개를 만들었다. 하지만 한 프로젝트에서 리듀서를 여러개 사용하려면 하나로 합쳐서 사용해야 한다. 이렇게 하나로 합친 리듀서를 루트 리듀서라고 부르며 리듀서들은 리덕스에 내장되어 있는 combineReducers 함수를 사용해서 합칠 수 있다.

modules 디렉터리에 index.js를 만들고 다음과 같이 코드를 작성해보자

modules/index.js

import { combineReducers } from "redux";
import counter from './counter';
import todos from './todos';

const rootReducer = combineReducers({
    counter,
    todos
});

export default rootReducers;

이렇게 하면 counter 모듈과 todos 모듈이 합쳐지게 된다!!

리덕스 스토어를 만드는 작업은 src 디렉터리의 index.js에서 진행한다.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {createStore} from 'redux';
import rootReducer from './modules';

const store = createStore(rootReducer);
console.log(store.getState());

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();

브라우저에서 코드를 실행하고 콘솔문을 확인해보면 state가 정상적으로 출력되는 것을 알 수 있다

 

리액트 프로젝트에 리덕스 적용하기

먼저, 터미널에 다음과 같은 명령어를 입력해 react-redux 라이브러리를 설치한다.

$ yarn add react-redux

이후에 index.jsProvider 컴포넌트를 불러와 App 컴포넌트를 감싸준다. 

그리고 Providerpropsstore를 넣어준다.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {createStore} from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';

const store = createStore(rootReducer);

ReactDOM.render(
  <Provider stpre={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

reportWebVitals();

여기까지 진행했다면 리덕스를 사용하기 위한 모든 준비가 끝났다.

 

참고

벨로퍼트와 함께하는 모던 리액트 https://react.vlpt.us/redux/04-make-modules.html