코딩/리액트

[새싹 성동 2기] useReducer를 활용한 상태 관리

insu90 2024. 12. 6. 18:03

 

React에서 상태 관리를 더 효율적으로 할 수 있는 훅(Hook) 중 하나가 바로 useReducer입니다. 이 훅은 상태 관리가 복잡해질 때 useState의 대체품으로 유용하게 사용될 수 있습니다. useReducer는 주로 여러 상태 값이나 복잡한 상태 로직을 다룰 때 그 유용성을 발휘합니다.

이번 글에서는 useState와 useReducer를 활용한 다양한 상태 관리 예제를 소개하고, 이를 통해 어떻게 상태를 더 깔끔하게 관리할 수 있는지 알아보겠습니다.

 

useState와 useReducer 비교

1. useState 사용법

useState는 간단한 상태 값을 관리할 때 사용됩니다. 아래 예제는 카운터를 관리하는 간단한 React 컴포넌트입니다.

import { useState } from "react";

const Counter = () => {
  const [count, setCount] = useState(0); // 상태 변수 'count'와 이를 업데이트할 함수 'setCount'
  
  const changeCount = e => setCount(count + Number(e.target.innerText));  // 버튼의 텍스트를 숫자로 변환하여 카운트 업데이트
  
  return (
    <>
      <h1>현재 카운트 값: {count}</h1>
      <button onClick={changeCount}>+1</button>
      <button onClick={changeCount}>-1</button>
    </>
  );
};

const App = () => <Counter />;
export default App;

 

위 코드에서는 useState를 사용하여 count 상태를 관리하고, 버튼을 클릭할 때마다 상태 값을 변경합니다.

 

2. useReducer 사용법

useReducer는 상태 변경 로직이 복잡할 때 유용한 훅입니다. 상태와 액션을 받아 새로운 상태를 반환하는 리듀서(reducer) 함수를 사용하여 상태를 관리합니다. useReducer는 두 개의 반환값을 가집니다:

  • 상태(현재 상태 값)
  • 디스패치 함수(액션을 리듀서에 전달해 상태를 업데이트하는 함수)
import { useReducer } from "react";

// 리듀서 함수 정의: 상태와 액션을 받아 새로운 상태를 반환
function reducer(state, action) {
  switch (action.type) {
    case "PLUSONE":
      return { count: state.count + 1 };
    case "MINUSONE":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { count: 0 });  // 상태 초기화

  return (
    <>
      <h1>현재 카운트 값: {state.count}</h1>
      <button onClick={() => dispatch({ type: "PLUSONE" })}>하나 증가</button>
      <button onClick={() => dispatch({ type: "MINUSONE" })}>하나 감소</button>
    </>
  );
};

const App = () => <Counter />;
export default App;

위 코드에서는 useReducer를 사용해 count 상태를 관리하고, 액션 타입을 PLUSONE, MINUSONE으로 정의하여 카운트를 증가시키거나 감소시킬 수 있습니다.

 

3. 추가적인 액션과 동적 값 처리

다음 예제에서는 useReducer를 활용해 숫자 값을 동적으로 조정할 수 있도록 구현해 보겠습니다. 버튼을 클릭하면 1 또는 5를 더하거나 뺄 수 있습니다.

import { useReducer } from "react";

// 리듀서 함수 정의: action.value에 따라 카운트 값을 변화시킴
function reducer(state, action) {
  switch (action.type) {
    case "PLUS":
      return { count: state.count + action.value };
    case "MINUS":
      return { count: state.count - action.value };
    default:
      return state;
  }
}

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

  return (
    <>
      <h1>현재 카운트 값: {state.count}</h1>
      <button onClick={() => dispatch({ type: "PLUS", value: 1 })}>하나 증가</button>
      <button onClick={() => dispatch({ type: "MINUS", value: 1 })}>하나 감소</button>
      <button onClick={() => dispatch({ type: "PLUS", value: 5 })}>다섯 더하기</button>
      <button onClick={() => dispatch({ type: "MINUS", value: 5 })}>다섯 빼기</button>
    </>
  );
};

const App = () => <Counter />;
export default App;

 

여기서는 버튼을 클릭할 때마다 value 값을 동적으로 PLUS 또는 MINUS 액션에 전달하여 count 값을 1 또는 5씩 증가시키거나 감소시킵니다.

 

useEffect와 useReducer의 결합

useEffect 훅은 컴포넌트의 생애주기(lifecycle)에 맞춰 특정 작업을 실행할 수 있게 해주는 훅입니다. 상태 값이 변경될 때마다 특정 작업을 수행하거나, 컴포넌트가 언마운트될 때 클린업 작업을 할 수 있습니다. useReducer와 함께 사용할 때도 유용합니다.

아래 예제에서는 이름과 별명 상태를 useReducer로 관리하고, useEffect를 통해 상태가 변경될 때마다 로그를 출력합니다.

import { useEffect, useReducer } from "react";

// 리듀서 함수 정의: 'name'과 'nickname' 값을 처리
function reducer(state, action) {
  switch (action.type) {
    case "name":
    case "nickname":
      return { ...state, [action.type]: action.value };
    default:
      return state;
  }
}

function Info() {
  const [state, dispatch] = useReducer(reducer, { name: '', nickname: '' });

  useEffect(() => {
    console.log("name 상태변수가 변경되었습니다.");
    console.log({ name: state.name, nickname: state.nickname });

    return () => console.log("cleanup", state.name);
  }, [state.name]);  // 'name'이 변경될 때마다 실행

  return (
    <>
      <div>
        <p>이름: {state.name}</p>
        <p>별명: {state.nickname}</p>
      </div>
      <div>
        <p>이름: <input type="text" value={state.name} onChange={e => dispatch({ type: "name", value: e.target.value })} /></p>
        <p>별명: <input type="text" value={state.nickname} onChange={e => dispatch({ type: "nickname", value: e.target.value })} /></p>
      </div>
    </>
  );
}

const App = () => <Info />;
export default App;

위 예제에서는 이름과 별명 상태를 useReducer로 관리하고, useEffect를 사용해 상태 변경을 추적합니다. 상태가 변경될 때마다 콘솔에 로그를 출력하고, 컴포넌트가 언마운트될 때 클린업 작업을 수행합니다.

 

useReducer는 상태 변화가 복잡해지거나 여러 상태를 다룰 때 useState보다 더 나은 선택이 될 수 있습니다. 리듀서 함수와 액션을 활용하여 상태를 업데이트하고, useEffect를 통해 상태 변경을 추적하거나 클린업 작업을 할 수 있습니다. useReducer를 잘 활용하면 React 컴포넌트의 상태 관리가 훨씬 깔끔하고 효율적으로 개선될 수 있습니다.

 

*생성형 AI 활용한 클라우드&보안 전문가 양성캠프 과정의 교육내용 정리 자료입니다