useReducer

한슬희·2023년 4월 16일
3

react

목록 보기
3/3
post-thumbnail

본 게시물은 useReducer에 대해 알아본 내용을 공유합니다.

useReducer란?

useReducer란 useState의 대체 함수로 상태 관리 hook 입니다.

useState가 있는데 왜 useReducer이 있는 걸까? 🤔

컴포넌트 안에서 관리해야 하는 상태 값이 많아지고 구조가 복잡해진다면 useReducer를 사용하는 것이 하나의 방법이 될 수 있습니다.

왜냐하면 useState는 컴포넌트 내부에서 로직을 작성했지만 useReducer는 컴포넌트 밖에서 작성할 수 있으며 다른 파일에 작성해 불러와 사용할 수도 있습니다.

아래는 간단한 예시로 내부, 외부만 확인하고 자세한 내용은 다음 세션에서 확인하실 수 있습니다.

useState

function Counter(){
  const [number, setNumber] = useState<number>(0)
  
  const onIncrease = () => {
    setNumber((prev) => prev + 1);
  }
  
  const onDecrease = () => {
    setNumber((prev) => prev - 1);
  }
}

내부에 존재하는 모습

useReducer

function reducer(state, action) {
  switch(action.type){
    case "INCREASE":
      return state + 1;
    case "DECREASE":
      return state - 1;
    default:
      throw new Error();
  }
}

function Counter(){
  const [number, dispatch] = useReducer(reducer, 0);
  return (
    <>
      <h1>Count: {number}</h1>
      <button onClick={() => dispatch({type: "INCREASE"})}>+</button>
      <button onClick={() => dispatch({type: "DECREASE"})}>-</button>
    </>
    )
}

즉, useReducer은 state 업데이트 로직을 분리하여 컴포넌트 외부에 작성하는 것이 가능합니다.

따라서 둘 중 뭘 써야 하는 지에 대한 정답은 없지만 플젝에 따라 어떤 것을 쓰는 게 관리에 용이한 지 생각해보면 될 것 같습니다.

useReducer 사용법

기본적으로 useReducer은 아래와 같은 형태로 사용합니다.

const [state, dispatch] = useReducer(reducer, inititalState)
const [상태, action을 발생시킬 함수] = useReducer(reducer 함수, 초기 상태)

dispatch

dispatch 함수는 reducer 함수를 실행시킵니다.

dispatch 함수 내부의 값은 객체 형태입니다.
객체 내부에서는 상태 업데이트를 구분하는 type을 사용합니다.

dispatch({ type: "내용" });

action

action은 dispatch의 인자이며 reducer 함수의 두 번째 인자 action에 할당됩니다.

참고사항으로 type의 값을 대문자와 언더바로 구성하는 관습이 있다고 합니다.

reducer 함수

reducer 함수는 dispatch 함수에 의해 실행됩니다.

reducer 함수는 state(현재 상태), action(업데이트와 관련된 정보를 가진 객체)을 파라미터로 받아와 새로운 상태를 반환해주는 함수입니다.

function reducer(state, action){
	return ...
}

reducer 함수는 action 값에 따라 새로운 state를 반환합니다.

switch말고 if-else를 사용해도 상관없습니다.

function reducer(state, action) {
  switch (action.type){
    case "increase": // action의 type이 increase 일 때
      return state + 1;
    case "decrease": // action의 type이 decrease 일 때
      return state - 1;
    default:
      throw new Error();
  }
}

또한 reducer 함수 이름은 useReducer를 선언할 때 reducer 함수와 같아야 합니다.

function reducer(state, action){
}


function Counter(){
  const [state, dispatch] = useReducer(reducer, 초기값);
}

useReducer 예시

useReducer로 Counter 컴포넌트를 만들어보자

myReducer.ts

type State = {
  count: number;
};

export type Action = { type: "INCREASE" } | { type: "DECREASE" };

export const initialState: State = {
  count: 0,
};

export function reducer(state: State, action: Action) {
  switch (action.type) {
    case "INCREASE":
      return { ...state, count: state.count + 1 };
    case "DECREASE":
      return { ...state, count: state.count - 1 };
  }
}

Counter.tsx

import { useReducer } from "react";
import { initialState, reducer } from "./myReducer";

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const onIncrease = () => dispatch({ type: "INCREASE" });
  const onDecrease = () => dispatch({ type: "DECREASE" });

  return (
    <div>
      <p>{state.count}</p>
      <button onClick={onIncrease}>increase</button>
      <button onClick={onDecrease}>decrease</button>
    </div>
  );
}

export default Counter;

useReducer와 useState

클릭 시 increase 하는 컴포넌트를 useReducer와 useState 두 가지 방식을 각각 이용해 적용해보자

useReducer

myReducer.ts

type State = {
  count: number;
};

export type Action = { type: "INCREASE" };

export const initialState = { count: 0 };

export function reducer(state: State, action: Action) {
  switch (action.type) {
    case "increase":
      return { ...state, count: state.count + 1 };
  }
}

Counter.tsx

import { useReducer } from "react";
import { initialState, reducer } from "./myReducer";

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const onClick = () => dispatch({ type: "INCREASE" });

  return (
    <div>
      <p>count: {state.count}</p>
      <button onClick={onClick}>increase</button>
    </div>
  );
}

export default Counter;

useState

Counter.tsx

import { useState } from "react";

function Counter() {
  const [number, setNumber] = useState(0);

  const onClick = () => setNumber(number + 1);

  return (
    <div>
      <p>count: {number}</p>
      <button onClick={onClick}>increase</button>
    </div>
  );
}

export default Counter;

마무리

설명하는 과정에서 혹시나 잘못된 부분이 있을 시 피드백 부탁드립니다.

글 읽어주셔서 감사합니다! 🙂

profile
🧡 Frontend developer / 어제보다 오늘 더 성장한 개발자

2개의 댓글

comment-user-thumbnail
2023년 4월 16일

잘보고가요~

1개의 답글