하루살이 개발일지

Redux의 이해 : createSlice에서 reducer와 reducers의 차이 본문

웹개발/React

Redux의 이해 : createSlice에서 reducer와 reducers의 차이

harusari 2023. 7. 4. 10:35

전개 - 에러와 궁금증

const initialState = {
  number: 0,
};

const counterSlice = createSlice({
  name: "counter",
  initialState,
  reducers: {
    addNumber: (state, action) => {
      state.number = state.number + action.payload;
    },
    minusNumber: (state, action) => {
      state.number = state.number - action.payload;
    },
  },
});

const { addNumber, minusNumber } = counterSlice.actions;
const counterReducer = counterSlice.reducer;

export { addNumber, minusNumber, counterReducer };
  • 위와 같은 코드에서, createSlice의 인자로 보내는 객체 안의 key 이름은 reducers인데, counterReducer를 정의하는 부분에서는 reducer를 사용하는 것이 이해가 되지 않았음
  • counterReducer 부분에서 reducer 대신 reducers라고 복수형을 보내면 에러가 발생하게 됨

이해를 돕는 쉬운 설명 - 야구 게임의 비유

Redux 주요 개념

  • State(상태)
    • 현재 경기장에 있는 모든 선수들과 공의 위치
    • 예를 들어, 각 선수가 어디에 있고, 공이 어떤 선수에게 있고, 점수판은 어떤 상태인지 등을 나타내는 정보
  • Action(액션)
    • 선수들이 공을 어떻게 움직일지, 어떤 행동을 취할지 나타내는 지시
    • 예를 들어, 타자가 치는 행동, 투수가 공을 던지는 행동 등
  • Reducer(리듀서)
    • 심판 역할
    • 선수들이 어떤 액션을 취하면 그에 따라 상태를 어떻게 바꿀 지 결정
    • 예를 들어, 타자가 공을 치면 어디로 공이 향할지, 어떤 선수가 공을 찹을 지, 점수를 어떻게 바꿀 지 등을 결정

 

configStore.js

export const store = configureStore({
  reducer: {
    counterReducer,
  },
});
  • configStore.js
    • 경기장을 준비하는 역할
    • 이 곳에서 counterReducer(심판)를 준비했음

 

counter.js

const initialState = {
  number: 0,
};

const counterSlice = createSlice({
  name: "counter",
  initialState,
  reducers: {
    addNumber: (state, action) => {
      state.number = state.number + action.payload;
    },
    minusNumber: (state, action) => {
      state.number = state.number - action.payload;
    },
  },
});

const { addNumber, minusNumber } = counterSlice.actions;
const counterReducer = counterSlice.reducer;

export { addNumber, minusNumber, counterReducer };
  • counter.js
    • 선수들이 공을 어떻게 다루는지 액션(addNumber, minusNumber)을 정의
    • 심판인 counterReducer를 생성
      • counterReducer는 선수들의 액션을 받아서 상태(state)를 어떻게 바꿀지 결정
  • reducers
    • 각 선수들의 액션을 정의하는 곳
    • 각 선수들이 공을 어떻게 움직이는지를 알려주는 규칙이 여기에 모여 있음
  • reducer
    • 이 모든 액션을 통합하여 관리하는 심판
    • 단수형으로 표현되는 이유는, 결국 심판은 한 명이기 때문
    • 여러 선수들의 액션을 관리하지만, 결정을 내리는 심판은 한 명

 

App.js

function App() {
  const count = useSelector((state) => state.counterReducer.number);
  const dispatch = useDispatch();

  const handleAddButtonClick = () => {
    dispatch(addNumber(1));
  };
  const handleMinusButtonClick = () => {
    dispatch(minusNumber(1));
  };

  return (
    <div>
      <h2>{count}</h2>
      <button onClick={handleAddButtonClick}>+</button>
      <button onClick={handleMinusButtonClick}>-</button>
    </div>
  );
}

export default App;
  • App.js
    • 실제 경기를 진행하는 곳
    • 선수들이 어떤 액션을 취할지 결정 (addNumber 또는 minusNumber를 dispatch하는 부분)
      • 선수들은 '+' 버튼을 누르면 'addNumber' 액션, '-' 버튼을 누르면 'minusNumber' 액션
      • 이 결정을 통해 상태가 변경되면, 그 변경된 상태는 다시 화면에 표시되어야
        • App.js는 useSelector를 사용해 현재 상태를 가져와 화면에 표시
    • 현재 상태를 화면에 보여줍니다(count 값을 출력하는 부분)

진짜 설명 - 궁금증 해소

  • 결국 createSlice에서 reducers가 뭐고 reducer는 뭐고 actions는 뭔데?
const initialState = {
  number: 0,
};

const counterSlice = createSlice({
  name: "counter",
  initialState,
  reducers: {
    addNumber: (state, action) => {
      state.number = state.number + action.payload;
    },
    minusNumber: (state, action) => {
      state.number = state.number - action.payload;
    },
  },
});

const { addNumber, minusNumber } = counterSlice.actions;
const counterReducer = counterSlice.reducer;

export { addNumber, minusNumber, counterReducer };
  • createSlice 함수
    • 개발자가 제공한 reducers 객체를 기반으로 actions 객체와 reducer 함수를 반환
    • 이 둘을 포함한 객체를 반환
  • reducers 객체
    • createSlice에 전달되는 인자의 일부. 즉 입력
    • 내부에 정의된 각각의 함수는 상태 업데이트 로직을 담고 있음
  • actions와 reducer
    • createSlice에서 반환되는 출력. 입력된 reducers에서 파생된 것이지만, 각각 다른 역할과 목적
      • actions : 개발자가 정의한 여러 reducers에 대응하는 액션 생성자들을 모아 놓은 객체
      • reducer : 개발자가 정의한 모든 reducer*를 하나로 합친 리듀서 함수 (실제로 상태를 업데이트하는 함수)