React-Redux 모듈 관리 및 Reducer 예제

React-Redux 모듈 관리 및 Reducer 예제

Redux 모듈 관리 및 Redux 예제, UnitTest


1. Redux 스토어 모듈 관리

  • Redux 스토어 구조

    1
    2
    3
    4
    5
    6
    7
    8
    9
    store/ // 스토어 엔트리 (스토어 생성)
    index.js

    actions/
    index.js // 액션 엔트리 (Action 내보내기)
    actionTypes.js // 액션 타입

    reducers/
    index.js // 리듀서 엔트리

    #상태 업데이트 구독과 취소 — store.subscribe() 메서드

  • 서브스크립션이란

    • APP 상태 변경을 구독(subscribe, 감지)하여 상태가 업데이트 되면 등록된 리스너를 실행시킨다.
  • click()이벤트와 같이 상태가 업데이트 될 때 구독을 하면 상태가 업데이트 될때 어떤 부분이 업데이트 되는지 알수 있다.

  • React-Redux 라이브러리를사용하면 서브스크립션은 자동 처리된다.


2. Reducer(리듀서) 함수


  • 리듀서는 액션을 전달 받아 상태를 교체하는 순수 함수이다.

TodoReducer 함수 — 작성

  • Rdeucer 생성 시

    • store/reducers파일 내에 reducer에 해당하는 todosReducer.js파일을 생성 후 작성을 해준다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      import {
      ADD_TODO,
      REMOVE_TODO,
      RESET_TODO,
      REPLACE_TODO,
      } from '../actions/actionTypes';

      export const initialState = [
      'Redux 라이브러리 설치',
      'Redux 아케텍처 이해',
      ];

      export const todosReducer = (state = initialState, { type, todo }) => {
      switch (type) {
      case ADD_TODO:
      state = [...state, todo];
      break;
      case REMOVE_TODO:
      state = state.filter(item => item !== todo);
      break;
      case RESET_TODO:
      state = initailState;
      break;
      case REPLACE_TODO:
      if (item === todo.item) {
      //todo = {item,replaceItem}
      return todo.replaceItem;
      }
      return item;
      break;
      default:
      console.log(
      '일치하는 액션 타입이 존재하지 않습니다. 확인 후 다시 시도해주세요'
      );
      }
      return state;
      };
    • store/actions/actionTypes.js파일 내에

      1
      2
      3
      4
      5
      6
      export const CHANGE_DATA = 'CHANGE_DATA';

      export const ADD_TODO = 'ADD_TODO';
      export const REMOVE_TODO = 'REMOVE_TODO';
      export const RESET_TODO = 'RESET_TODO';
      export const REPLACE_TODO = 'REPLACE_TODO';

      TodoReducer 함수 — 유닛 테스트

  • Reducer Unit test 코드 짜는 법

  • 다음과 같이 요청 하나하나에 대한 요청에 테스트를 해주어야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import {
ADD_TODO,
REMOVE_TODO,
RESET_TODO,
REPLACE_TODO,
} from '../actions/actionTypes';

import { initialState, todosReducer } from './todosReducer';

// Unit Test
it('todosReducer 함수의 ADD_TODO 액션은 올바르게 작동하는가?', () => {
const addTodoTestValue = '액션과 액션 타입 활용';
const addTodoTest = todosReducer(todos, {
type: ADD_TODO,
todo: addTodoTestValue,
});
expect(todoTest).toEqual([...todos, addTodoTestValue]);
});

it('todosReducer 함수의 REMOVE_TODO 액션은 올바르게 작동하는가?', () => {
const removeTodoTestValue = '액션과 액션 타입 활용';
const removeTodoTest = todosReducer(todos, {
type: REMOVE_TODO,
todo: removeTodoTestValue,
});
expect(removeTodoTest).toEqual(
todos.filter(todo => todo !== removeTodoTestValue)
);
});

it('todosReducer 함수의 RESET_TODO 액션은 올바르게 작동하는가?', () => {
const resetTodoTest = todosReducer(todos, {
type: RESET_TODO,
});
expect(resetTodoTest).toEqual(todos);
});

it('todosReducer 함수의 REPLACE_TODO 액션은 올바르게 작동하는가?', () => {
const replaceTodoTestValue = {
item: '액션과 액션 타입 활용',
replaceItem: 'React Redux 활용',
};
const replaceTodoTest = todosReducer(todos, {
type: REPLACE_TODO,
todo: replaceTodoTestValue,
});
expect(replaceTodoTest).toEqual([
'액션과 액션 타입 활용',
'React Redux 활용',
]);
});

3. Redux 패턴 리뷰


  • .createStore(reducer) : 스토어 생성(reducer)
  • store.getState() : 스토어 상태 반환
  • store.dispatch(action) : 스토어 상태 변경 전달(액션)
  • store.subscribe(listener) : 스토어 상태 반경 감지(리스너)

.createStore(reducer) 작동원리

  • .createStore(reducer)은 다음과 같이 작동합니다.
  • 다음과 같은 createStore()함수를 봤을 때 reducer는 단지 일반적인 함수일 뿐이고 메서드로 state와 action을 받아 사용한다.
  • dispatch메서드는 reducer힘수에서 전달 받은 state와 action을 받아 state를 업데이트를 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// import { createStore } from 'redux';
// createStore(reducer) => store {};
// store = {getState, subscribe, dispatch};

const createStore = reducer => {
let state; // 외부에서는 접근이 불가한 데이터

// 데이터 반환 메서드
const getState = () => state;

let listenrs = []; // 등록된 리스너(함수) 보관하는 리스트(배열)

// 구독(업데이트 실행 함수 연결) 메서드
const subscribe = listener => {
listeners.push(listener);
// 구독 취소 (업데이트 실행 함수 제거) 메서드 반환
return removeListener => {
listeners = listeners.filter(listener => listener !== removeListener);
};
};

// 디스패치(알림, 업데이트 요청) 메서드
const dispatch = action => {
// state 업데이트
state = reducer(state, action);

// listeners의 모든 listener를 실행
listeners.forEach(listener => listener());
};
return { getState, subscribe, dispatch };
};

React-Redux 모듈 관리 및 Reducer 예제

https://youngheakim.github.io/Redux/reduxModule/

Author

YoungHea Kim

Posted on

2021-05-20

Updated on

2021-05-20

Licensed under