[ React ] useReducer 살펴보기

·2024년 2월 17일

1. useReducer

useReducer란 useState를 대체하는 함수로, useState의 심화 버전이다.
useReducer는 reducer를 이용하여 컴포넌트의 상태 로직을 관리한다.

2. useReducer 사용 용어

2.1 반환값

  • state : 현재 useReducer가 가지고 있는 값(컴포넌트에서 사용할 상태)으로 useState와 마찬가지로 배열을 반환하는데 동일하게 첫 번째 요소가 이 값이다.
  • dispatch: state를 업데이트하는 함수로, useReducer가 반환하는 배열의 두 번째 요소이다. setState는 단순히 값을 넘겨주지만, useReducer에서는 action을 넘겨준다. action은 state를 변경하는 액션을 의미한다.

2.2 인수

  • reducer : useReducer의 기본 action을 정의하는 함수, 첫 번째 인수이다.
  • initialState: useReducer의 초깃값을 의미하며, 두 번째 인수이다.
  • init: 초깃값을 지연해서 생성시키고 싶을 때 사용하는 함수로, 세 번째 인수이다. 필수값이 아니며, 인수로 넘겨주는 함수가 존재한다면 useState와 동일하게 게으른 초기화가 일어나, initalState를 인수로 init 함수가 실행된다.

3. useReducer 사용하기

const [ state, dispatch ] = useReducer(reducer, initalState, init);

3.1 dispatch

reducer 함수를 실행시키며, action객체를 인자로 받는다.
즉, reducer 함수가 실행 ( state를 업데이트하는 로직을 실행) 되도록, 요구 하는 행위
이때 요구의 내용을 action이라고 명명한다.
즉, action을 사용하여 state의 업데이트를 일으킨다.

  • action: 어떤 행동인지를 나타내는 type 속성과 해당 행동과 관련된 데이터(payload)를 담고 있다.

3.2 reducer

dispatch 함수에 의해 실행되며, 컴포넌트 외부에서 state를 업데이트하는 로직을 담당한다.
함수의 인자로는 state와 action을 받게 된다.
state와 action을 활용하여 새로운 state를 반환한다.
즉, action의 내용대로 state를 업데이트함

3.3 그림으로 정리하기


3.4 예시코드

import React, { useReducer } from "react";

//컴포넌트 밖에서 reducer 함수를 정의한다.
function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT":
      return { count: state.count + action.payload };
    case "DECREMENT":
      return { count: state.count - action.payload };
    default:
      throw new Error("unsupported action type: ", action.type);
  }
}

const Counter = () => {
  const initialState = { count: 0 };
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <>
      <h2>{state.count}</h2>
      <button onClick={() => dispatch({ type: "INCREMENT", payload: 1 })}>
        증가
      </button>
      <button onClick={() => dispatch({ type: "DECREMENT", payload: 1 })}>
        감소
      </button>
      <button onClick={() => dispatch({ type: "kkkkkkkkk", payload: 1 })}>
        에러
      </button>
    </>
  );
};

export default Counter;

이때, init함수를 세 번째 인자로 전달하면 초기 state는 init에 설정된다.

import React, { useReducer } from "react";

function init(initialState) {
  return { count: initialState };
}

function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT":
      return { count: state.count + action.payload };
    case "DECREMENT":
      return { count: state.count - action.payload };
    case "RESET":
      //init 함수 사용
      return init(action.payload);
    default:
      throw new Error("unsupported action type: ", action.type);
  }
}

const Counter = ({ initialCount }) => {
  const [state, dispatch] = useReducer(reducer, initialCount, init);

  return (
    <>
      <h2>{state.count}</h2>
      <button onClick={() => dispatch({ type: "RESET", payload: 0 })}>
        초기화
      </button>
      <button onClick={() => dispatch({ type: "INCREMENT", payload: 1 })}>
        증가
      </button>
      <button onClick={() => dispatch({ type: "DECREMENT", payload: 1 })}>
        감소
      </button>
      <button onClick={() => dispatch({ type: "kkkkkkkkk", payload: 1 })}>
        에러
      </button>
    </>
  );
};

export default Counter;

4. useReducer 사용 목적

useReducer의 목적은 복잡한 형태의 state를 사전에 정의된 dispatch로만 수정할 수 있게 하여, state 값에 대한 접근은 컴포넌트에서만 가능하게 하고,
업데이트하는 방법에 대한 상세 정의를 컴포넌트 밖으로 분리한다.
이를 통해, state의 업데이트를 미리 정의해 둔 dispatcher로만 제한한다.
즉, state값을 변경하는 시나리오를 제한적으로 두고 이에 대한 변경을 빠르게 확인할 수 있게끔 하는 것이 useReducer의 목적이다.

여러 개의 하위값을 가지는 state의 경우의 수가 많아지면 비슷한 성격의 state를 묶어 useReducer로 관리하는 것이 효율적이다.
init 함수가 없다면 두 번째 인수로 넘겨받은 기본값을 사용하게 된다.
init 함수가 있다면 useState에 함수를 넣은 것과 같은 이점을 누릴 수 있고, state에 대한 초기화가 필요할 때 reducer에서 재사용할 수 있다.

  • useState 사용시
  • useReducer 사용시
profile
new blog: https://hae0-02ni.tistory.com/

0개의 댓글