UseReducer로 상태관리

장현욱(Artlogy)·2022년 8월 22일
0

React

목록 보기
15/24
post-thumbnail

지금 까지 상태를 업데이트 할 때에는 useState를 사용해서 새로운 상태를 설정해주었지만
useState말고 useReducer를 사용하는 방법도 존재한다. useState는 해당 컴포넌트에서만 관리 가능하지만 useReducer는 컴포넌트에서 밖이나 다른 파일에서 로직 분리가 가능하다.

예전에 useState를 익히기 위해 만들어둔 CounterButton.jsx를 사용해 배워보자.

CounterButton.jsx

import React, { useState } from "react";

const CounterButton = () => {
    const [counter, setCounter] = useState(0);
    return (
        <>
            <div>{counter}</div>
            <button
                onClick={() => {
                    setCounter(counter + 1);
                }}
            >
                증가
            </button>
            <button
                onClick={() => {
                    setCounter(counter - 1);
                }}
            >
                감소
            </button>
        </>
    );
};

export default CounterButton;

UseReducer

function reducer(state, action){
//새로운 상태를 만드는 로직을 넣으면된다.
  
  return nextState;
}

useReducer는 대게 위와 같은 형태가 기본이라고 생각하면 된다.
현재 상태와 액션 객체를 파라미터로 받아와 새로운 상태를 반환해준다.
reducer에서 반환하는 상태가 컴포넌트들이 지닐 새로운 상태가 된다.
여기서 action은 업데이트를 위한 정보를 가지고 있다.

액션의 예시는 다음과 같다.

//카운터에 1을 더하는 액션
{
  type:"INCREMENT"
}
//카운터에 1을 빼는 액션
{
  type:"DECREMENT"
}
//INPUT값을 바꾸는 액션
{
  type:"CHANGE_INPUT",
  key:"email",
  value:"change@email.com"
}
// 새 할 일을 등록하는 액션
{
  type: 'ADD_TODO',
  todo: {
    id: 1,
    text: 'useReducer 배우기',
    done: false,
  }
//

action 객체의 위 처럼 자유롭게 정하면 된다. type값을 대문자 스네이크케이스로 작성하는 관습이 있긴한데 꼭 그렇게 안해도된다. 우리가 REST API를 사용할때 서버쪽에 BODY데이터를 보낼때를 생각하면된다.

이제 reducer의 형태를 봤으니 사용해보자.

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

여기서 state는 앞으로 컴포넌트에서 사용한 상태값을 뜻하고, dispatch는 액션을 발생시키는 함수라고 생각하면된다. dispatch({type:"INCREMENT"})처럼 사용한다.

그리고 useReducer에 첫번째 파라미터는 reducer 함수를 넣고, 두번째 파라미터엔 초기상태를 넣어주면된다.

이제 useState로 구현한 CounterButton컴포넌트를 useReducer로 구현해보겠다.

import React, { useReducer, useState } from "react";

function reducer(state, action) {
    switch (action.type) {
        case "INCREMENT":
            return state + 1;
        case "DECREMENT":
            return state - 1;
        default:
            return state;
    }
}

const CounterButton = () => {
    const [counter, dispatch] = useReducer(reducer, 0);
    return (
        <>
            <div>{counter}</div>
            <button
                onClick={() => {
                    dispatch({ type: "INCREMENT" });
                }}
            >
                증가
            </button>
            <button
                onClick={() => {
                    dispatch({ type: "DECREMENT" });
                }}
            >
                감소
            </button>
        </>
    );
};

export default CounterButton;

useReducer vs useState

여기까지 왔다면 궁금한점이 하나 생기셨을것이다.
그럼 어떨때 useState를 쓰거나 useReducer를 써야할까?
솔직히 정답은 없다. 편한대로 쓰면된다. 하지만 필자의 경험을 들어 예를 들자면
간단한 값이나 해당 컴포넌트에서만 쓰는 값이라면 useState를 쓰는게 좋고
객체처럼 복잡한 값을 관리해야 하거나 다양한 컴포넌트에서 쓸 가능성이 있는
상태는 useReducer를 쓰는게 좋다.

0개의 댓글