FE

[FE]useReducer 이해하기

팝삐 2024. 8. 25. 17:02

 

useReducer

  • useReducer()을 는 상태와 그 상태를 업데이트하는 함수를 반환하는 React 훅입니다. 이 훅은 상태를 업데이트하는 로직을 함수 형태로 분리해 관리한다.
  • useReducer은 기본적으로 Redux에서 사용하는 패턴과 유사하게 동작하며, 상태 변경 로직을 컴포넌트 외부로 분리할 수 있어 상태 관리가 복잡해질 때 매우 유용하다.
const [state, dispatch] = useReducer(reducer, initialState);
  • reducer
    • 현재 상태와 액션을 기반으로 새로운 상태를 반환하는 함수
  • initialState
    • 초기 상태 값
  • state
    • 현재 상태를 나타낸다.
  • dispatch
    • 상태를 변경하기 위한 액션을 발생시키는 함수

useReducer의 역할

  • 복잡한 상태 관리
    • useState를 사용하면 여러 상태 변수를 개별적으로 관리해야 하는 경우가 많은데, useReducer을 사용하면 상태와 그 변화를 하나의 함수에서 관리할 수 있어 복잡한 상태 로직을 쉽게 다룰 수 있다.
  • 코드 가독성 향상
    • 상태 변화를 관리하는 로직을 reducer 함수로 분리하기 때문에 코드가 더 깔끔하고 가독성이 높아진다.
  • 유지보수성 개선
    • 상태 변경 로직이 한 곳에 모이므로, 유지보수와 테스트가 용이하다.

useState ⇒ useReducer

useState

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default Counter;

useReducer

import React, { useReducer } from 'react';

// reducer 함수 정의
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

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

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
}

export default Counter;
  • reducer 함수는 현재 상태와 액션을 인자로 받아, 새로운 상태를 반환한다.
  • dispatch 함수를 사용해 액션을 발생시키고, 이를 통해 상태를 변경한다.

useReducer 사용

  • 복잡한 상태 로직이 필요한 경우
    • 상태 업데이트 로직이 여러 가지 경우를 처리해야 할 때 useState가 더 적합하다.
    • 여러 상태 변수나 다양한 액션 타입이 필요한 경우
  • 상태 관리의 일관성
    • 상태 변경 로직을 하나의 reducer 함수에 통합하면, 코드의 일관성을 유지하고 버그를 줄일 수 있다.

useReducer 객체 관리

import React, { useReducer } from 'react';

// reducer 함수
function reducer(state, action) {
  switch (action.type) {
    case 'setName':
      return { ...state, name: action.payload };
    case 'setAge':
      return { ...state, age: action.payload };
    case 'toggleIsStudent':
      return { ...state, isStudent: !state.isStudent };
    default:
      throw new Error('Unknown action');
  }
}

function UserProfile() {
  const initialState = { name: '', age: 0, isStudent: false };
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Name: {state.name}</p>
      <p>Age: {state.age}</p>
      <p>Is Student: {state.isStudent ? 'Yes' : 'No'}</p>

      <input
        type="text"
        placeholder="Set Name"
        onChange={(e) => dispatch({ type: 'setName', payload: e.target.value })}
      />
      <input
        type="number"
        placeholder="Set Age"
        onChange={(e) => dispatch({ type: 'setAge', payload: parseInt(e.target.value) })}
      />
      <button onClick={() => dispatch({ type: 'toggleIsStudent' })}>
        Toggle Is Student
      </button>
    </div>
  );
}

export default UserProfile;
  • reducer를 통해 객체 안의 요소를 상태 관리할 수 있다.

결론

  • useReducer은 useState보다 더 복잡한 상태 관리가 필요할 때 유용한 도구이다.
  • 상태 업데이트 로직이 복잡해지거나 다양한 경우를 처리해야 한다면, useReducer로 전환하여 관리할 수 있다.