็„ก์ œ

useReducer (์œ ์ฆˆ๋ฆฌ๋“€์„œ) ๋ณธ๋ฌธ

<React>

useReducer (์œ ์ฆˆ๋ฆฌ๋“€์„œ)

yo-u-loo 2026. 7. 15. 12:50

 

๐ŸŸก useReducer

๋ณต์žกํ•œ ์ƒํƒœ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ React Hook.

useState๋Š” ๊ฐ„๋‹จํ•œ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋ฉฐ, ์—ฌ๋Ÿฌ ์ƒํƒœ๊ฐ€ ์„œ๋กœ ์—ฐ๊ด€๋˜๊ฑฐ๋‚˜ ์ƒํƒœ ๋ณ€๊ฒฝ ๋กœ์ง์ด ๋ณต์žกํ•œ ๊ฒฝ์šฐ์—๋Š” useReducer๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

โ—ผ๏ธ ํ•„์š” ์ด์œ 

useState๋Š” ๊ฐ„๋‹จํ•œ ์ƒํƒœ ๊ด€๋ฆฌ์—๋Š” ์ ํ•ฉํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ๋Š” ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

1๏ธโƒฃ ์—ฌ๋Ÿฌ ์ƒํƒœ๊ฐ€ ์„œ๋กœ ์—ฐ๊ด€๋œ ๊ฒฝ์šฐ

์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ƒํƒœ๊ฐ€ ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•œ๋‹ค๋ฉด useState๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [author, setAuthor] = useState("");
  • ์ƒํƒœ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ๊ด€๋ฆฌํ•˜๊ธฐ ์–ด๋ ค์›Œ์ง„๋‹ค.

 

2๏ธโƒฃ ์ƒํƒœ ๋ณ€๊ฒฝ ๋กœ์ง์ด ๋ณต์žกํ•œ ๊ฒฝ์šฐ

์กฐ๊ฑด์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ํ•จ๊ป˜ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜, ์ƒํƒœ ๋ณ€๊ฒฝ ๋กœ์ง์ด ๋งŽ์•„์งˆ์ˆ˜๋ก ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€ ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์ง„๋‹ค.

 

๐Ÿ‘‰ useReducer๋Š” ์ด๋Ÿฌํ•œ ์ƒํƒœ ๋ณ€๊ฒฝ ๋กœ์ง์„ ๋ณ„๋„์˜ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

โ—ผ๏ธ ์ฃผ์š” ํŠน์ง•

  • ๋ณต์žกํ•œ ์ƒํƒœ ๋กœ์ง
    • ์—ฌ๋Ÿฌ ํ•˜์œ„ ๊ฐ’์œผ๋กœ ๊ตฌ์„ฑ๋œ ๋ณต์žกํ•œ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค. 
  • ์„œ๋กœ ๊ด€๋ จ๋œ ์ƒํƒœ
    • ํ•œ ์ƒํƒœ์˜ ๋ณ€๊ฒฝ์ด ๋‹ค๋ฅธ ์ƒํƒœ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ฑฐ๋‚˜, ์—ฌ๋Ÿฌ ์ƒํƒœ๊ฐ€ ๋™์‹œ์— ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์ƒํƒœ ๋กœ์ง ๋ถ„๋ฆฌ
    • ์ƒํƒœ ์—…๋ฐ์ดํŠธ ๋กœ์ง์„ ์ปดํฌ๋„ŒํŠธ ๋ฐ–์œผ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์žฌ์‚ฌ์šฉ์„ฑ
    • ๋™์ผํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋กœ์ง์„ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

โ—ผ๏ธ ํ•ต์‹ฌ ๊ฐœ๋…

๐Ÿ”น reducer

์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝํ• ์ง€ ์ •์˜ํ•˜๋Š” ํ•จ์ˆ˜.

ํ˜„์žฌ ์ƒํƒœ(state)์™€ ์•ก์…˜(action)์„ ๋ฐ›์•„ ์ƒˆ๋กœ์šด ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

    default:
      return state;
  }
}

 

๐Ÿ”น State

ํ˜„์žฌ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

state.count

 

๐Ÿ”น action

์–ด๋–ค ์ƒํƒœ ๋ณ€๊ฒฝ์„ ํ•  ๊ฒƒ์ธ์ง€ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ์ฒด์ด๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ type ์†์„ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค.

{
  type: "INCREMENT"
}
  • ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๋ฅผ ํ•จ๊ป˜ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
{
  type: "ADD",
  payload: 10
}

 

๐Ÿ”น dispatch

Reducer์—๊ฒŒ Action์„ ์ „๋‹ฌํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.

dispatch({ type: "INCREMENT" });

 

โ—ผ๏ธ ๊ธฐ๋ณธ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

useReducer๋Š” state์™€ dispatch๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, reducer ํ•จ์ˆ˜์™€ ์ดˆ๊ธฐ ์ƒํƒœ(initialState)๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.

1๏ธโƒฃ Reducer ํ•จ์ˆ˜ ์ž‘์„ฑ → 2๏ธโƒฃ useReducer ์‚ฌ์šฉ → 3๏ธโƒฃ dispatch๋กœ ์ƒํƒœ ๋ณ€๊ฒฝ

import React, { useReducer } from 'react';

// 1. Reducer ํ•จ์ˆ˜ ์ •์˜
// ์ด ํ•จ์ˆ˜๋Š” '์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฐ”๊ฟ€์ง€' ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
// currentState: ํ˜„์žฌ ์ƒํƒœ
// action: ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ–ˆ๋Š”์ง€ (๊ฐ์ฒด ํ˜•ํƒœ, ์ฃผ๋กœ type ์†์„ฑ ํฌํ•จ)
function reducer(currentState, action) {
  switch (action.type) {
    case 'INCREMENT': // 'INCREMENT' ์•ก์…˜์ด ์˜ค๋ฉด
      return { count: currentState.count + 1 }; // count๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚จ ์ƒˆ ์ƒํƒœ ๋ฐ˜ํ™˜
    case 'DECREMENT': // 'DECREMENT' ์•ก์…˜์ด ์˜ค๋ฉด
      return { count: currentState.count - 1 }; // count๋ฅผ 1 ๊ฐ์†Œ์‹œํ‚จ ์ƒˆ ์ƒํƒœ ๋ฐ˜ํ™˜
    case 'RESET': // 'RESET' ์•ก์…˜์ด ์˜ค๋ฉด
      return { count: 0 }; // count๋ฅผ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ ์ƒˆ ์ƒํƒœ ๋ฐ˜ํ™˜
    default:
      return currentState; // ์•Œ ์ˆ˜ ์—†๋Š” ์•ก์…˜์€ ์—๋Ÿฌ ๋ฐœ์ƒ
  }
}

// 2. ์ปดํฌ๋„ŒํŠธ์—์„œ useReducer ์‚ฌ์šฉ
function Counter() {
  // useReducer(reducer ํ•จ์ˆ˜, ์ดˆ๊ธฐ ์ƒํƒœ)
  // useReducer๋Š” [ํ˜„์žฌ ์ƒํƒœ, dispatch ํ•จ์ˆ˜]๋ฅผ ๋ฐ˜ํ™˜
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>ํ˜„์žฌ ์นด์šดํŠธ: {state.count}</p>
      {/* 3. dispatch ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์•ก์…˜ ์ „๋‹ฌ */}
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>์ฆ๊ฐ€</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>๊ฐ์†Œ</button>
      <button onClick={() => dispatch({ type: 'RESET' })}>์ดˆ๊ธฐํ™”</button>
    </div>
  );
}

export default Counter;

 

 

๐Ÿ“‹ useState vs useReducer ๐Ÿ“‹

useState useReducer
๊ฐ„๋‹จํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ณต์žกํ•œ ์ƒํƒœ ๊ด€๋ฆฌ
์ƒํƒœ ๋ณ€๊ฒฝ ๋กœ์ง์ด ๋‹จ์ˆœํ•จ ์ƒํƒœ ๋ณ€๊ฒฝ ๋กœ์ง์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌ
์ž‘์€ ํ”„๋กœ์ ํŠธ์— ์ ํ•ฉ ์—ฌ๋Ÿฌ ์ƒํƒœ๋ฅผ ํ•จ๊ป˜ ๊ด€๋ฆฌํ•  ๋•Œ ์ ํ•ฉ
์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ด ๊ฐ„๋‹จํ•จ reducer์™€ dispatch๋ฅผ ์‚ฌ์šฉ