항해 16기/Today I Learned

[항해 22일차] TIL_React 숙련주차 : Redux-Refactoring(action creators, action values)

해갈 2023. 9. 4. 21:14

학습 목표

기존 Redux 프로젝트를 Action creators 와 Action values 로 재구성할 수 있습니다.

 

Action Creator

Action Creator 란?

만약 액션객체의 value 를 변경할 일이 생긴다면 어떨까요? 

PLUS_ONE, MINUS_ONE 이라는 value 대신 두 액션객체가 counter 모듈 안에 있다는 것을 강조하기 위해 counter/PLUS_ONE, counter/MINUS_ONE 이라는 value 로 각각 바꾸길 원한다면, 아래 코드에서 4군데를 변경해줘야 할 것입니다. 4군데는 번거로운 수준이지만, 바꿔야 할 변수가 10개가 넘어가면 해당 코드는 바껴야 되겠죠.

src/App.js

// src/App.js

import React from "react";
import { useDispatch, useSelector } from "react-redux";

const App = () => {
  const dispatch = useDispatch();
  const number = useSelector((state) => state.counter.number);

  return (
    <div>
      {number}
      <button
        onClick={() => {
          dispatch({ type: "PLUS_ONE" }); // counter/PLUS_ONE로 변경
        }}
      >
        + 1
      </button>
      <button
        onClick={() => {
					// 액션객체 디스패치
          dispatch({ type: "MINUS_ONE" }); // counter/MINUS_ONE로 변경
        }}
      >
        - 1
      </button>
    </div>
  );
};

export default App;

src/modules/counter.js

// src/modules/counter.js

// 초기 상태값
const initialState = {
  number: 0,
};

// 리듀서
const counter = (state = initialState, action) => {
  switch (action.type) {
    case "PLUS_ONE": // counter/PLUS_ONE로 변경
      return {
        number: state.number + 1,
      };

		// action.type이 MINUS_ONE 일 때 새로운 state 반환
    case "MINUS_ONE": // counter/MINUS_ONE로 변경
      return {
        number: state.number - 1,
      };
    default:
      return state;
  }
};

// 모듈파일에서는 리듀서를 export default 한다.
export default counter;

 

Action Creator 만들기

그래서 앞으로는 위 코드처럼 직접 하드코딩을 하는 것이 아니라, 액션객체를 한 곳에서 관리할 수 있도록 "함수" 와 액션 value 를 상수로 만들어보겠습니다.

만약 PLUS_ONE 이라는 액션 객체를 만드는 함수를 만든다면, 아래와 같이 만들 수 있습니다. 그리고 이것을 액션을 만드는 생성자, Action Creator 로 부릅니다.

src/redux/modules/counter.js

// src/redux/modules/counter.js

const PLUS_ONE = "PLUS_ONE"; // value는 상수로 생성

// 액션객체를 반환하는 함수 생성
// export 가 붙는 이유는 plusOne()는 밖으로 나가서 사용될 예정이기 때문입니다.
export const plusOne = () => { 
  return {
    type: PLUS_ONE, // type에는 위에서 만든 상수로 사용 (vscode에서 자동완성 지원)
  };
};

이렇게 액션의 value 는 상수로 따로 만들어주고, 만든 상수를 이용해서 액션객체를 반환하는 함수를 작성합니다. 이것을 실제로 리듀서와 컴포넌트에서는 아래와 같이 작성합니다.

src/modules/counter.js

// src/modules/counter.js

// 추가된 코드 👇 - 액션 value를 상수들로 만들어 줍니다. 보통 이렇게 한곳에 모여있습니다.
const PLUS_ONE = "PLUS_ONE";
const MINUS_ONE = "MINUS_ONE";


// 추가된 코드 👇 - Action Creator를 만들어 줍니다. 
export const plusOne = () => {
  return {
    type: PLUS_ONE,
  };
};

export const minusOne = () => {
  return {
    type: MINUS_ONE,
  };
};


// 초기 상태값
const initialState = {
  number: 0,
};

// 리듀서
const counter = (state = initialState, action) => {
  switch (action.type) {
    case PLUS_ONE: // case에서도 문자열이 아닌, 위에서 선언한 상수를 넣어줍니다. 
      return {
        number: state.number + 1,
      };
    case MINUS_ONE: // case에서도 문자열이 아닌, 위에서 선언한 상수를 넣어줍니다. 
      return {
        number: state.number - 1,
      };
    default:
      return state;
  }
};


export default counter;

모듈에 initialState 와 리듀서밖에 없었지만, 액션의 value  Action Creator 가 추가되었습니다.

 

Action Creator 사용하기

생성한 Action Creator 를 컴포넌트에서 어떻게 사용하는지 알아보겠습니다. 사용하는 방법은 아래순서로 진행합니다.

  1. export 된 Action Creator import 하기
  2. dispatch() 에 있던 액션객체를 지우고, Action Creator 넣기

하나씩 코드로 보겠습니다.

src/App.js

// src/App.js

import React from "react";
import { useDispatch, useSelector } from "react-redux";

// 사용할 Action creator를 import 합니다.
import { minusOne, plusOne } from "./redux/modules/counter";

const App = () => {
  const dispatch = useDispatch();
  const number = useSelector((state) => state.counter.number);

  return (
    <div>
      {number}
      <button
        onClick={() => {
          dispatch(plusOne()); // 액션객체를 Action creator로 변경합니다.
        }}
      >
        + 1
      </button>
      {/* 빼기 버튼 추가 */}
      <button
        onClick={() => {
          dispatch(minusOne()); // 액션객체를 Action creator로 변경합니다.
        }}
      >
        - 1
      </button>
    </div>
  );
};

export default App;
우선 사용할 Action Creator 를 import 해야 합니다. Action Creator 는 태생적으로 counter.js 밖에서 사용될 함수들이었습니다. 그래서 생성할 때부터 앞에 export 를 붙여준 것이었습니다.
그리고 dispatch() 안에 있던 액션객체를 import 한 Action Creator 들로 변경해줍니다.
 Q. dispatch()안에는 반드시 객체만 들어가야 한다고 알고 있는데, 어떻게 함수가 들어갈 수 있을까요?

A. {type: “PLUS_ONE”} === plusOne() 는 같은 값입니다. 함수를 실행한 것은 함수의 return 값과 같습니다. 다시 말해, const one = () => {return 1; } 로 함수를 만들었을 때 one() === 1 입니다.

 

Action Creator 를 사용하는 이유

1) 휴먼 에러(오타) 방지

액션 객체의 type value 를 상수로 만들어놓았기 때문에, 개발툴에서 자동완성등의 기능을 지원받을 수 있습니다. 그래서 의도치 않은 휴먼에러(오타)를 줄일 수 있습니다.

2) 유지보수의 효율성 증가

생성한 Action Creator 가 만약 100군데 이상 쓰이고 있는 상태에서 혹여나 변수명을 바꾸어야 하는 상황이 오더라도 단 한번의 수정으로 100군데에 모든 수정사항을 반영할 수 있습니다.

3) 코드 가독성

모듈 파일에서 Action Creator 가 일목요연하게 정리가 되어있으면, 본인이 아닌 다른 개발자가 보았을 때 해당 모듈이 가지고 있는 모든 Action 들을 한 눈에 알 수 있게 됩니다. 즉 그 자체가 Action 들의 리스트업을 해주는 역할을 갖게 되는 것입니다.

4) 리덕스 공식문서에서 소개되고 있는 방법

리덕스팀에서도 물론 위와 같은 사유에 근거해 공식적으로 안내하고 있는 방법일 것입니다.

 

정리해서

액션객체를 만드는 함수를 Action Creator(액션 크리에이터)라고 합니다.

Action Creator 는 모듈 파일 안에서 생성됩니다.

액션객체의 type value 로 상수로 생성해서 관리합니다.

Action Creator 를 사용하면, 여러가지 문제점을 해소할 수 있습니다.