본문 바로가기
개발/React

React_ reducer 란..

by JunsC 2025. 2. 27.
728x90

UserReducer 에 대해 고찰해보자..

새로고침 후 데이터가 휘발성으로 증발되어 다시 새롭게 작성해야하는 문제가 있다.

영속성이 없어진 것이다.. ..

이럴때 보통 reduce-persistance 등 사용하여 영속성을 추가해준다. 세션에 저장하거나 

그래서 이부분에 대한 기술적인 고찰을 한번 해볼겸 끄적끄적 거려본다.

 

 

Reducer

 

useReducer는 React에서 상태를 관리할 때 사용하는 훅(Hook)으로, 복잡한 상태 로직을 관리할 때 useState보다 더 강력한 기능을 제공합니다.

📌 Reducer란?

useReducer는 상태(state)와 그 상태를 변경하는 로직을 분리하여 관리하는 방식을 제공합니다.
Redux와 비슷한 개념으로, 액션(action)을 발생시키고, 이를 처리하는 리듀서(reducer) 함수를 이용하여 상태를 업데이트합니다.

 

 

✨ useReducer 기본 구조

const [state, dispatch] = useReducer(reducer, initialState);
  • reducer → 상태를 변경하는 함수
  • initialState → 초기 상태 값
  • state → 현재 상태
  • dispatch → 액션을 발생시키는 함수

 

🔹 useReducer 기본 예제: 숫자 증가/감소 카운터

import React, { useReducer } from "react";

// 1️⃣ 리듀서 함수 정의
const reducer = (state, action) => {
  switch (action.type) {
    case "INCREMENT":
      return { count: state.count + 1 };
    case "DECREMENT":
      return { count: state.count - 1 };
    case "RESET":
      return { count: 0 };
    default:
      return state;
  }
};

const Counter = () => {
  // 2️⃣ useReducer 사용
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <h1>Count: {state.count}</h1>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>+1</button>
      <button onClick={() => dispatch({ type: "DECREMENT" })}>-1</button>
      <button onClick={() => dispatch({ type: "RESET" })}>Reset</button>
    </div>
  );
};

export default Counter;

🔍 코드 설명

  1. 리듀서 함수 (reducer)
    • state와 action을 받아서 새로운 상태를 반환함.
    • switch 문을 사용하여 액션에 따라 상태를 업데이트.
  2. useReducer를 사용하여 상태 관리 (state, dispatch)
    • dispatch({ type: "INCREMENT" }) → action.type이 "INCREMENT"인 객체를 리듀서로 보냄.
    • 리듀서가 이를 처리하여 새로운 state 반환.

🔹 useState vs useReducer 언제 사용할까?

useState vs useReducer

간단한 상태 (ex. true/false, count) 복잡한 상태 로직 (ex. 객체, 배열)
독립적인 상태 변경 여러 상태가 연관되어 변경될 때
상태 변경 로직이 간단함 상태 변경 로직이 복잡할 때 (if, switch 등)

 

 

🎯 useReducer 활용 예제 2: Todo 리스트 관리

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

// 리듀서 함수 정의
const todoReducer = (state, action) => {
  switch (action.type) {
    case "ADD":
      return [...state, { id: Date.now(), text: action.text }];
    case "REMOVE":
      return state.filter((todo) => todo.id !== action.id);
    default:
      return state;
  }
};

const TodoApp = () => {
  const [todos, dispatch] = useReducer(todoReducer, []);
  const [input, setInput] = useState("");

  const addTodo = () => {
    if (input.trim() === "") return;
    dispatch({ type: "ADD", text: input });
    setInput("");
  };

  return (
    <div>
      <h1>Todo List</h1>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={addTodo}>추가</button>
      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>
            {todo.text} <button onClick={() => dispatch({ type: "REMOVE", id: todo.id })}>삭제</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoApp;

🔍 코드 설명

  • "ADD" 액션을 사용하면 새로운 할 일을 추가함.
  • "REMOVE" 액션을 사용하면 특정 id를 가진 할 일을 삭제함.
  • useState를 함께 사용하여 입력 필드를 관리함.

 

🎯 useReducer 활용 예제 3: 비동기 API 호출 (useEffect + useReducer)

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

const initialState = {
  loading: true,
  data: null,
  error: null,
};

// 리듀서 정의
const reducer = (state, action) => {
  switch (action.type) {
    case "SUCCESS":
      return { loading: false, data: action.payload, error: null };
    case "ERROR":
      return { loading: false, data: null, error: action.error };
    default:
      return state;
  }
};

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

  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts/1")
      .then((response) => response.json())
      .then((data) => dispatch({ type: "SUCCESS", payload: data }))
      .catch((error) => dispatch({ type: "ERROR", error }));
  }, []);

  return (
    <div>
      {state.loading && <p>Loading...</p>}
      {state.error && <p>Error: {state.error}</p>}
      {state.data && <h1>{state.data.title}</h1>}
    </div>
  );
};

export default FetchData;
 

🔍 코드 설명

  • useEffect에서 API를 호출하고 데이터를 가져옴.
  • "SUCCESS" 액션 → 데이터를 성공적으로 가져오면 상태 업데이트.
  • "ERROR" 액션 → API 호출 실패 시 에러 처리.

 

🎯 useReducer 사용 시 유용한 패턴

  1. 액션 타입을 상수로 관리하면 실수 방지 가능
const INCREMENT = "INCREMENT";
const DECREMENT = "DECREMENT";
const RESET = "RESET";

const reducer = (state, action) => {
  switch (action.type) {
    case INCREMENT:
      return { count: state.count + 1 };
    case DECREMENT:
      return { count: state.count - 1 };
    case RESET:
      return { count: 0 };
    default:
      return state;
  }
};

 

 

  1. 상태 로직을 컴포넌트 밖으로 분리하면 관리가 쉬워짐
 
const reducer = (state, action) => { ... };

// 컴포넌트
const MyComponent = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
};

 

 

✅ 정리

✔ useReducer는 복잡한 상태 관리에 적합함
✔ dispatch(action)을 사용하여 상태를 변경
✔ reducer(state, action) 함수에서 상태 변경 로직을 관리
✔ useEffect와 함께 사용하면 비동기 처리도 가능

 

끄읕 ~~~

'개발 > React' 카테고리의 다른 글

React_ Semantic 구조  (2) 2024.08.07
React_ npm module @types 의 의미  (0) 2024.07.29
React 프로젝트 생성 feat. Typescript  (0) 2024.06.13
React 무한 스크롤  (0) 2024.06.10
React 새로고침 데이터 저장  (1) 2024.06.09
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."