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;
🔍 코드 설명
- 리듀서 함수 (reducer)
- state와 action을 받아서 새로운 상태를 반환함.
- switch 문을 사용하여 액션에 따라 상태를 업데이트.
- 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 사용 시 유용한 패턴
- 액션 타입을 상수로 관리하면 실수 방지 가능
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;
}
};
- 상태 로직을 컴포넌트 밖으로 분리하면 관리가 쉬워짐
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 |