코딩/React

Redux - Refactoring(action creators, action values)

junhub 2023. 4. 19. 10:12

# Action Creator

 

1. Action Creator 란?

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

PLUS_ONE , MINUS_ONE 이라는 value 대신 이 액션객체가 counter 모듈안에 있다는 것을 강조하기 위해서 counter/PLUS_ONE, counter/MINUS_ONE 이라는 value로 바꾸길 각각 바꾸길 원한다면 아래 코드에서 4군데를 변경해줘야 할 것이다.

근데 또 만약에 그게 4군데가 아니라 프로젝트 규모가 굉장히 커서 100군데라면 수정해야 할 부분이 굉장히 많아질 것이다. 

// 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

// 초기 상태값
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;

 

 

 

2. Action Creator 만들기

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

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

// src/redux/modules/counter.js

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

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

이렇게 액션의 value는 상수로 따로 만들어주고, 그리고 그것을 이용해서 액션객체를 반환하는 함수를 작성한다.

아래 리듀서 전체 코드를 보면 모듈에 initialState와 리듀서밖에 없었지만 액션의 value와 Action Creator가 추가되었다. 

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

 

 

 

3. Action Creator 사용하기

우리가 생성한 Action Creator를 컴포넌트에서 사용하는 방법은 아래와 같다.

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

우선 사용할 Action creator를 import 해야 합니다. 즉 Action creator는 태생적으로 counter.js 밖에서 사용될 함수들이었던 것이다. 그래서 생성할때부터 앞에 export 를 붙여준 것이다.

그리고 dispatch()안에 있던 액션객체를 import 한 Action Creator들로 변경해준다. 이렇게 하면 수정이 모두 끝났다. 

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

 

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 들의 리스트업을 해주는 역할을 갖게 되는 것이다. 

 

 

 

 

# 정리

  • 액션객체를 만드는 함수를 Action Creator(액션 크리에이터)라고 한다.
  • Action Creator는 모듈 파일안에서 생성된다.
  • 액션객체의 type value로 상수로 생성해서 관리한다.
  • Action Creator를 사용하면, 여러가지 문제점을 해소할 수 있다.