Reactμ useReducer ν μ ν΅ν΄ 볡μ‘ν μν κ΄λ¦¬λ₯Ό νμνμΈμ. μ΄ κ°μ΄λλ μ μΈκ³ κ°λ°μλ₯Ό μν κ³ κΈ ν¨ν΄, μ±λ₯ μ΅μ ν λ° μ€μ μ¬λ‘λ₯Ό λ€λ£Ήλλ€.
React useReducer: 볡μ‘ν μν κ΄λ¦¬ ν¨ν΄ λ§μ€ν°νκΈ°
Reactμ useReducer ν
μ μ ν리μΌμ΄μ
μμ 볡μ‘ν μνλ₯Ό κ΄λ¦¬νκΈ° μν κ°λ ₯ν λꡬμ
λλ€. κ°λ¨ν μν μ
λ°μ΄νΈμ μ ν©ν useStateμ λ¬λ¦¬, useReducerλ 볡μ‘ν μν λ‘μ§κ³Ό μ΄μ μνμ μμ‘΄νλ μ
λ°μ΄νΈλ₯Ό μ²λ¦¬νλ λ° νμν©λλ€. μ΄ ν¬κ΄μ μΈ κ°μ΄λλ useReducerμ 볡μ‘μ±μ κΉμ΄ νκ³ λ€κ³ , κ³ κΈ ν¨ν΄μ νμνλ©°, μ μΈκ³ κ°λ°μλ₯Ό μν μ€μ©μ μΈ μμ λ₯Ό μ 곡ν κ²μ
λλ€.
useReducerμ κΈ°λ³Έ μ΄ν΄
λ³Έμ§μ μΌλ‘ useReducerλ Redux ν¨ν΄μμ μκ°μ λ°μ μν κ΄λ¦¬ λꡬμ
λλ€. μ΄ ν
μ 리λμ ν¨μμ μ΄κΈ° μνλΌλ λ κ°μ§ μΈμλ₯Ό μ·¨ν©λλ€. 리λμ ν¨μλ λμ€ν¨μΉλ μ‘μ
μ λ°λΌ μν μ νμ μ²λ¦¬ν©λλ€. μ΄ ν¨ν΄μ λͺ¨λ κ·λͺ¨μ μ ν리μΌμ΄μ
μ νμμ μΈ λ κΉλν μ½λ, μ¬μ΄ λλ²κΉ
λ° μμΈ‘ κ°λ₯ν μν μ
λ°μ΄νΈλ₯Ό μ΄μ§ν©λλ€. κ΅¬μ± μμλ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€:
- 리λμ ν¨μ: μ΄κ²μ΄
useReducerμ ν΅μ¬μ λλ€. νμ¬ μνμ μ‘μ κ°μ²΄λ₯Ό μ λ ₯μΌλ‘ λ°μ μ μνλ₯Ό λ°νν©λλ€. μ‘μ κ°μ²΄λ μΌλ°μ μΌλ‘ μνν μ‘μ μ μ€λͺ νλtypeμμ±μ κ°μ§λ©°, μΆκ° λ°μ΄ν°λ₯Ό ν¬ν¨νλpayloadλ₯Ό ν¬ν¨ν μ μμ΅λλ€. - μ΄κΈ° μν: μ΄κ²μ μ ν리μΌμ΄μ μνμ μμμ μ λλ€.
- λμ€ν¨μΉ ν¨μ: μ΄ ν¨μλ μ‘μ
μ λμ€ν¨μΉνμ¬ μν μ
λ°μ΄νΈλ₯Ό νΈλ¦¬κ±°ν μ μκ² ν©λλ€. λμ€ν¨μΉ ν¨μλ
useReducerμ μν΄ μ 곡λ©λλ€.
κΈ°λ³Έ ꡬ쑰λ₯Ό 보μ¬μ£Όλ κ°λ¨ν μμ μ λλ€:
import React, { useReducer } from 'react';
// Define the reducer function
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
// Initialize useReducer
const [state, dispatch] = useReducer(reducer, { count: 0 });
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;
μ΄ μμ μμ 리λμ ν¨μλ μ¦κ° λ° κ°μ μ‘μ
μ μ²λ¦¬νμ¬ `count` μνλ₯Ό μ
λ°μ΄νΈν©λλ€. dispatch ν¨μλ μ΄λ¬ν μν μ νμ νΈλ¦¬κ±°νλ λ° μ¬μ©λ©λλ€.
κ³ κΈ useReducer ν¨ν΄
κΈ°λ³Έ useReducer ν¨ν΄μ κ°λ¨νμ§λ§, λ 볡μ‘ν μν λ‘μ§μ λ€λ£¨κΈ° μμν λ κ·Έ μ§μ ν νμ΄ λλ¬λ©λλ€. κ³ λ €ν΄μΌ ν λͺ κ°μ§ κ³ κΈ ν¨ν΄μ λ€μκ³Ό κ°μ΅λλ€:
1. 볡μ‘ν μ‘μ νμ΄λ‘λ
μ‘μ μ 'increment' λλ 'decrement'μ κ°μ κ°λ¨ν λ¬Έμμ΄μΌ νμκ° μμ΅λλ€. νλΆν μ 보λ₯Ό λ΄μ μ μμ΅λλ€. νμ΄λ‘λλ₯Ό μ¬μ©νλ©΄ λ λμ μΈ μν μ λ°μ΄νΈλ₯Ό μν΄ λ¦¬λμμ λ°μ΄ν°λ₯Ό μ λ¬ν μ μμ΅λλ€. μ΄λ νΌ, API νΈμΆ λ° λͺ©λ‘ κ΄λ¦¬μ λ§€μ° μ μ©ν©λλ€.
function reducer(state, action) {
switch (action.type) {
case 'add_item':
return { ...state, items: [...state.items, action.payload] };
case 'remove_item':
return { ...state, items: state.items.filter(item => item.id !== action.payload) };
default:
return state;
}
}
// Example action dispatch
dispatch({ type: 'add_item', payload: { id: 1, name: 'Item 1' } });
dispatch({ type: 'remove_item', payload: 1 }); // Remove item with id 1
2. μ¬λ¬ 리λμ μ¬μ© (리λμ μ‘°ν©)
λ ν° μ ν리μΌμ΄μ μ κ²½μ°, λ¨μΌ 리λμμμ λͺ¨λ μν μ νμ κ΄λ¦¬νλ κ²μ΄ λ€λ£¨κΈ° μ΄λ €μΈ μ μμ΅λλ€. 리λμ μ‘°ν©μ μν κ΄λ¦¬λ₯Ό λ μκ³ κ΄λ¦¬νκΈ° μ¬μ΄ μ‘°κ°μΌλ‘ λΆν΄ν μ μκ² ν΄μ€λλ€. μ¬λ¬ 리λμλ₯Ό λ¨μΌ μ΅μμ 리λμλ‘ κ²°ν©νμ¬ μ΄λ₯Ό λ¬μ±ν μ μμ΅λλ€.
// Individual Reducers
function itemReducer(state, action) {
switch (action.type) {
case 'add_item':
return { ...state, items: [...state.items, action.payload] };
case 'remove_item':
return { ...state, items: state.items.filter(item => item.id !== action.payload) };
default:
return state;
}
}
function filterReducer(state, action) {
switch(action.type) {
case 'SET_FILTER':
return {...state, filter: action.payload}
default:
return state;
}
}
// Combining Reducers
function combinedReducer(state, action) {
return {
items: itemReducer(state.items, action),
filter: filterReducer(state.filter, action)
};
}
// Initial state (Example)
const initialState = {
items: [],
filter: 'all'
};
function App() {
const [state, dispatch] = useReducer(combinedReducer, initialState);
return (
<div>
{/* UI Components that trigger actions on combinedReducer */}
</div>
);
}
3. Context APIμ useReducer νμ©
Context APIλ λͺ¨λ λ 벨μμ μλμΌλ‘ propsλ₯Ό μ λ¬ν νμ μμ΄ μ»΄ν¬λνΈ νΈλ¦¬λ₯Ό ν΅ν΄ λ°μ΄ν°λ₯Ό μ λ¬νλ λ°©λ²μ μ 곡ν©λλ€. useReducerμ κ²°ν©νλ©΄ κ°λ ₯νκ³ ν¨μ¨μ μΈ μν κ΄λ¦¬ μ루μ
μ μμ±νλ©°, μ’
μ’
Reduxμ κ²½λ λμμΌλ‘ κ°μ£Όλ©λλ€. μ΄ ν¨ν΄μ μ μ μ ν리μΌμ΄μ
μνλ₯Ό κ΄λ¦¬νλ λ° νΉν μ μ©ν©λλ€.
import React, { createContext, useContext, useReducer } from 'react';
// Create a context for our state
const AppContext = createContext();
// Define the reducer and initial state (as before)
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
const initialState = { count: 0 };
// Create a provider component
function AppProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<AppContext.Provider value={{ state, dispatch }}>
{children}
</AppContext.Provider>
);
}
// Create a custom hook for easy access
function useAppState() {
return useContext(AppContext);
}
function Counter() {
const { state, dispatch } = useAppState();
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
}
function App() {
return (
<AppProvider>
<Counter />
</AppProvider>
);
}
μ¬κΈ°μ AppContextλ λͺ¨λ μμ μ»΄ν¬λνΈμ μνμ λμ€ν¨μΉ ν¨μλ₯Ό μ 곡ν©λλ€. useAppState 컀μ€ν
ν
μ 컨ν
μ€νΈ μ κ·Όμ κ°μνν©λλ€.
4. Thunk ꡬν (λΉλκΈ° μ‘μ )
useReducerλ κΈ°λ³Έμ μΌλ‘ λκΈ°μ μ
λλ€. κ·Έλ¬λ λ§μ μ ν리μΌμ΄μ
μμ APIμμ λ°μ΄ν°λ₯Ό κ°μ Έμ€λ κ²κ³Ό κ°μ λΉλκΈ° μμ
μ μνν΄μΌ ν©λλ€. Thunkλ λΉλκΈ° μ‘μ
μ κ°λ₯νκ² ν©λλ€. μΌλ° μ‘μ
κ°μ²΄ λμ ν¨μ("thunk")λ₯Ό λμ€ν¨μΉνμ¬ μ΄λ₯Ό λ¬μ±ν μ μμ΅λλ€. μ΄ ν¨μλ `dispatch` ν¨μλ₯Ό λ°μ λΉλκΈ° μμ
κ²°κ³Όμ λ°λΌ μ¬λ¬ μ‘μ
μ λμ€ν¨μΉν μ μμ΅λλ€.
function fetchUserData(userId) {
return async (dispatch) => {
dispatch({ type: 'request_user' });
try {
const response = await fetch(`/api/users/${userId}`);
const user = await response.json();
dispatch({ type: 'receive_user', payload: user });
} catch (error) {
dispatch({ type: 'request_user_error', payload: error });
}
};
}
function reducer(state, action) {
switch (action.type) {
case 'request_user':
return { ...state, loading: true, error: null };
case 'receive_user':
return { ...state, loading: false, user: action.payload, error: null };
case 'request_user_error':
return { ...state, loading: false, error: action.payload };
default:
return state;
}
}
function UserProfile({ userId }) {
const [state, dispatch] = useReducer(reducer, { loading: false, user: null, error: null });
React.useEffect(() => {
dispatch(fetchUserData(userId));
}, [userId, dispatch]);
if (state.loading) return <p>Loading...</p>;
if (state.error) return <p>Error: {state.error.message}</p>;
if (!state.user) return null;
return (
<div>
<h2>{state.user.name}</h2>
<p>Email: {state.user.email}</p>
</div>
);
}
μ΄ μμ λ λΉλκΈ° API νΈμΆ μ€ λ‘λ©, μ±κ³΅ λ° μ€λ₯ μνμ λν μ‘μ μ λμ€ν¨μΉν©λλ€. λ 볡μ‘ν μλ리μ€μ κ²½μ° `redux-thunk`μ κ°μ λ―Έλ€μ¨μ΄κ° νμν μ μμ§λ§, κ°λ¨ν μ¬μ© μ¬λ‘μ κ²½μ° μ΄ ν¨ν΄μ΄ λ§€μ° μ μλν©λλ€.
μ±λ₯ μ΅μ ν κΈ°λ²
React μ ν리μΌμ΄μ
μ μ±λ₯ μ΅μ νλ νΉν 볡μ‘ν μν κ΄λ¦¬λ₯Ό λ€λ£° λ μ€μν©λλ€. useReducerλ₯Ό μ¬μ©ν λ μ μ©ν μ μλ λͺ κ°μ§ κΈ°μ μ λ€μκ³Ό κ°μ΅λλ€:
1. λμ€ν¨μΉ ν¨μ λ©λͺ¨μ΄μ μ΄μ
useReducerμμ λ°νλλ dispatch ν¨μλ μΌλ°μ μΌλ‘ λ λλ§ μ¬μ΄μ λ³κ²½λμ§ μμ§λ§, λΆνμν μ¬λ λλ§μ λ°©μ§νκΈ° μν΄ μμ μ»΄ν¬λνΈλ‘ μ λ¬νλ κ²½μ° λ©λͺ¨μ΄μ μ΄μ
νλ κ²μ΄ μ¬μ ν μ’μ λ°©λ²μ
λλ€. μ΄λ₯Ό μν΄ React.useCallbackμ μ¬μ©νμΈμ:
const [state, dispatch] = useReducer(reducer, initialState);
const memoizedDispatch = React.useCallback(dispatch, []); // Memoize dispatch function
μ΄λ κ² νλ©΄ dispatch ν¨μκ° μ’
μμ± λ°°μ΄μ μ’
μμ±μ΄ λ³κ²½λ λλ§ λ³κ²½λλλ‘ λ³΄μ₯ν©λλ€ (μ΄ κ²½μ° μ’
μμ±μ΄ μμΌλ―λ‘ λ³κ²½λμ§ μμ΅λλ€).
2. 리λμ λ‘μ§ μ΅μ ν
리λμ ν¨μλ λͺ¨λ μν μ λ°μ΄νΈ μ μ€νλ©λλ€. λΆνμν κ³μ°μ μ΅μννκ³ λ¦¬λμ ν¨μ λ΄μμ 볡μ‘ν μμ μ νΌνμ¬ λ¦¬λμκ° μ±λ₯μ λ°ννλλ‘ νμΈμ. λ€μμ κ³ λ €νμμμ€:
- λΆλ³ μν μ
λ°μ΄νΈ: νμ μνλ₯Ό λΆλ³μ μΌλ‘ μ
λ°μ΄νΈνμμμ€. μ€νλ λ μ°μ°μ (
...) λλObject.assign()μ μ¬μ©νμ¬ μ μν κ°μ²΄λ₯Ό λ§λμμμ€. μ΄λ λ³κ²½ κ°μ§ λ° μκΈ°μΉ μμ λμ λ°©μ§μ μ€μν©λλ€. - λΆνμν κΉμ λ³΅μ¬ λ°©μ§: μ λμ μΌλ‘ νμν κ²½μ°μλ§ μν κ°μ²΄μ κΉμ 볡μ¬λ₯Ό μννμμμ€. μμ λ³΅μ¬ (λ¨μ κ°μ²΄μ μ€νλ λ μ°μ°μ μ¬μ©)λ μΌλ°μ μΌλ‘ μΆ©λΆνλ©° κ³μ° λΉμ©μ΄ μ μ΅λλ€.
- μ§μ° μ΄κΈ°ν: μ΄κΈ° μν κ³μ°μ΄ κ³μ° λΉμ©μ΄ λ§μ΄ λλ κ²½μ°, ν¨μλ₯Ό μ¬μ©νμ¬ μνλ₯Ό μ΄κΈ°νν μ μμ΅λλ€. μ΄ ν¨μλ μ΄κΈ° λ λλ§ μ€μ ν λ²λ§ μ€νλ©λλ€.
//Lazy initialization
const [state, dispatch] = useReducer(reducer, initialState, (initialArg) => {
//Expensive initialization logic here
return {
...initialArg,
initializedData: 'data'
}
});
3. useMemoλ₯Ό μ¬μ©ν 볡μ‘ν κ³μ° λ©λͺ¨μ΄μ μ΄μ
μ»΄ν¬λνΈκ° μνμ κΈ°λ°ν κ³μ° λΉμ©μ΄ λ§μ΄ λλ μμ
μ μννλ κ²½μ°, React.useMemoλ₯Ό μ¬μ©νμ¬ κ²°κ³Όλ₯Ό λ©λͺ¨μ΄μ μ΄μ
νμΈμ. μ΄λ κ² νλ©΄ μ’
μμ±μ΄ λ³κ²½λμ§ μλ ν κ³μ°μ λ€μ μ€ννλ κ²μ λ°©μ§ν μ μμ΅λλ€. μ΄λ λκ·λͺ¨ μ ν리μΌμ΄μ
λλ 볡μ‘ν λ‘μ§μ κ°μ§ μ ν리μΌμ΄μ
μ μ±λ₯μ λ§€μ° μ€μν©λλ€.
import React, { useReducer, useMemo } from 'react';
function reducer(state, action) {
// ...
}
function MyComponent() {
const [state, dispatch] = useReducer(reducer, { items: [1, 2, 3, 4, 5] });
const total = useMemo(() => {
console.log('Calculating total...'); // This will only log when the dependencies change
return state.items.reduce((sum, item) => sum + item, 0);
}, [state.items]); // Dependency array: recalculate when items change
return (
<div>
<p>Total: {total}</p>
{/* ... other components ... */}
</div>
);
}
μ€μ useReducer μμ
useReducerμ λ€μ¬λ€λ₯ν¨μ 보μ¬μ£Όλ λͺ κ°μ§ μ€μ μ¬μ© μ¬λ‘λ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€. μ΄ μμ λ€μ μ μΈκ³ κ°λ°μλ€μκ² λ€μν νλ‘μ νΈ μ νμ κ±Έμ³ κ΄λ ¨μ΄ μμ΅λλ€.
1. νΌ μν κ΄λ¦¬
νΌμ λͺ¨λ μ ν리μΌμ΄μ
μ μΌλ°μ μΈ κ΅¬μ± μμμ
λλ€. useReducerλ μ¬λ¬ μ
λ ₯ νλ, μ ν¨μ± κ²μ¬ λ° μ μΆ λ‘μ§μ ν¬ν¨νμ¬ λ³΅μ‘ν νΌ μνλ₯Ό μ²λ¦¬νλ μ’μ λ°©λ²μ
λλ€. μ΄ ν¨ν΄μ μ μ§λ³΄μμ±μ λμ΄κ³ μμ©κ΅¬ μ½λλ₯Ό μ€μ
λλ€.
import React, { useReducer } from 'react';
function formReducer(state, action) {
switch (action.type) {
case 'change':
return {
...state,
[action.field]: action.value,
};
case 'submit':
//Perform submission logic (API calls, etc.)
return state;
case 'reset':
return {name: '', email: '', message: ''};
default:
return state;
}
}
function ContactForm() {
const [state, dispatch] = useReducer(formReducer, { name: '', email: '', message: '' });
const handleSubmit = (event) => {
event.preventDefault();
dispatch({type: 'submit'});
// Example API Call (Conceptual)
// fetch('/api/contact', { method: 'POST', body: JSON.stringify(state) });
alert('Form submitted (conceptually)!')
dispatch({type: 'reset'});
};
const handleChange = (event) => {
dispatch({ type: 'change', field: event.target.name, value: event.target.value });
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="name">Name:</label>
<input type="text" id="name" name="name" value={state.name} onChange={handleChange} />
<label htmlFor="email">Email:</label>
<input type="email" id="email" name="email" value={state.email} onChange={handleChange} />
<label htmlFor="message">Message:</label>
<textarea id="message" name="message" value={state.message} onChange={handleChange} />
<button type="submit">Submit</button>
</form>
);
}
export default ContactForm;
μ΄ μμ λ νΌ νλμ μνλ₯Ό ν¨μ¨μ μΌλ‘ κ΄λ¦¬νκ³ μ λ ₯ λ³κ²½ λ° νΌ μ μΆμ λͺ¨λ μ²λ¦¬ν©λλ€. μ±κ³΅μ μΈ μ μΆ ν νΌμ μ¬μ€μ νλ `reset` μ‘μ μ μ£Όλͺ©νμΈμ. κ°κ²°νκ³ μ΄ν΄νκΈ° μ¬μ΄ ꡬνμ λλ€.
2. μ₯λ°κ΅¬λ ꡬν
μ μΈκ³μ μΌλ‘ μΈκΈ° μλ μ μμκ±°λ μ ν리μΌμ΄μ
μ μ’
μ’
μ₯λ°κ΅¬λ κ΄λ¦¬λ₯Ό ν¬ν¨ν©λλ€. useReducerλ μ₯λ°κ΅¬λμ νλͺ©μ μΆκ°, μ κ±° λ° μ
λ°μ΄νΈνλ 볡μ‘μ±μ μ²λ¦¬νλ λ° νμνκ² μ ν©ν©λλ€.
function cartReducer(state, action) {
switch (action.type) {
case 'add_item':
const existingItemIndex = state.items.findIndex(item => item.id === action.payload.id);
if (existingItemIndex !== -1) {
// If item exists, increment the quantity
const updatedItems = [...state.items];
updatedItems[existingItemIndex] = { ...updatedItems[existingItemIndex], quantity: updatedItems[existingItemIndex].quantity + 1 };
return { ...state, items: updatedItems };
}
return { ...state, items: [...state.items, { ...action.payload, quantity: 1 }] };
case 'remove_item':
return { ...state, items: state.items.filter(item => item.id !== action.payload) };
case 'update_quantity':
const itemIndex = state.items.findIndex(item => item.id === action.payload.id);
if (itemIndex !== -1) {
const updatedItems = [...state.items];
updatedItems[itemIndex] = { ...updatedItems[itemIndex], quantity: action.payload.quantity };
return { ...state, items: updatedItems };
}
return state;
case 'clear_cart':
return { ...state, items: [] };
default:
return state;
}
}
function ShoppingCart() {
const [state, dispatch] = React.useReducer(cartReducer, { items: [] });
const handleAddItem = (item) => {
dispatch({ type: 'add_item', payload: item });
};
const handleRemoveItem = (itemId) => {
dispatch({ type: 'remove_item', payload: itemId });
};
const handleUpdateQuantity = (itemId, quantity) => {
dispatch({ type: 'update_quantity', payload: {id: itemId, quantity} });
}
// Calculate total
const total = React.useMemo(() => {
return state.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}, [state.items]);
return (
<div>
<h2>Shopping Cart</h2>
{state.items.length === 0 && <p>Your cart is empty.</p>}
<ul>
{state.items.map(item => (
<li key={item.id}>
{item.name} - ${item.price} x {item.quantity} = ${item.price * item.quantity}
<button onClick={() => handleRemoveItem(item.id)}>Remove</button>
<input type="number" min="1" value={item.quantity} onChange={(e) => handleUpdateQuantity(item.id, parseInt(e.target.value))} />
</li>
))}
</ul>
<p>Total: ${total}</p>
<button onClick={() => dispatch({ type: 'clear_cart' })}>Clear Cart</button>
{/* ... other components ... */}
</div>
);
}
μΉ΄νΈ λ¦¬λμλ νλͺ© μΆκ°, μ κ±° λ° μλ μ
λ°μ΄νΈλ₯Ό κ΄λ¦¬ν©λλ€. React.useMemo ν
μ μ΄ κ°κ²©μ ν¨μ¨μ μΌλ‘ κ³μ°νλ λ° μ¬μ©λ©λλ€. μ΄λ μ¬μ©μμ μ§λ¦¬μ μμΉμ κ΄κ³μμ΄ μΌλ°μ μ΄κ³ μ€μ©μ μΈ μμ
λλ€.
3. μꡬ μνλ₯Ό κ°μ§ κ°λ¨ν ν κΈ κ΅¬ν
μ΄ μμ λ useReducerμ λ‘컬 μ€ν 리μ§λ₯Ό κ²°ν©νμ¬ μꡬ μνλ₯Ό ꡬννλ λ°©λ²μ 보μ¬μ€λλ€. μ¬μ©μλ€μ μ’
μ’
μμ μ μ€μ μ΄ κΈ°μ΅λκΈ°λ₯Ό κΈ°λν©λλ€. μ΄ ν¨ν΄μ λΈλΌμ°μ μ λ‘컬 μ€ν 리μ§λ₯Ό μ¬μ©νμ¬ νμ΄μ§λ₯Ό μλ‘ κ³ μΉ νμλ ν κΈ μνλ₯Ό μ μ₯ν©λλ€. μ΄λ ν
λ§, μ¬μ©μ μ νΈλ λ±μ μ μλν©λλ€.
import React, { useReducer, useEffect } from 'react';
// Reducer function
function toggleReducer(state, action) {
switch (action.type) {
case 'toggle':
return { isOn: !state.isOn };
default:
return state;
}
}
function ToggleWithPersistence() {
// Retrieve the initial state from local storage or default to false
const [state, dispatch] = useReducer(toggleReducer, { isOn: JSON.parse(localStorage.getItem('toggleState')) || false });
// Use useEffect to save the state to local storage whenever it changes
useEffect(() => {
localStorage.setItem('toggleState', JSON.stringify(state.isOn));
}, [state.isOn]);
return (
<div>
<button onClick={() => dispatch({ type: 'toggle' })}>
{state.isOn ? 'On' : 'Off'}
</button>
<p>Toggle is: {state.isOn ? 'On' : 'Off'}</p>
</div>
);
}
export default ToggleWithPersistence;
μ΄ κ°λ¨ν μ»΄ν¬λνΈλ μνλ₯Ό ν κΈνκ³ ν΄λΉ μνλ₯Ό `localStorage`μ μ μ₯ν©λλ€. useEffect ν
μ λͺ¨λ μ
λ°μ΄νΈ μ μνκ° μ μ₯λλλ‘ λ³΄μ₯ν©λλ€. μ΄ ν¨ν΄μ μΈμ
κ° μ¬μ©μ μ€μ μ 보쑴νλ κ°λ ₯ν λꡬμ΄λ©°, μ΄λ μ μΈκ³μ μΌλ‘ μ€μν©λλ€.
useState λμ useReducerλ₯Ό μ ννλ μμ
useReducerμ useState μ€ λ¬΄μμ μ νν μ§λ μνμ 볡μ‘μ±κ³Ό λ³ν λ°©μμ λ°λΌ λ¬λΌμ§λλ€. μ¬λ°λ₯Έ μ νμ νλ λ° λμμ΄ λλ κ°μ΄λκ° μμ΅λλ€:
- λ€μκ³Ό κ°μ κ²½μ°
useReducerλ₯Ό μ ννμΈμ: - μν λ‘μ§μ΄ 볡μ‘νκ³ μ¬λ¬ νμ κ°μ ν¬ν¨νλ κ²½μ°.
- λ€μ μνκ° μ΄μ μνμ μμ‘΄νλ κ²½μ°.
- μλ§μ μ‘μ μ ν¬ν¨νλ μν μ λ°μ΄νΈλ₯Ό κ΄λ¦¬ν΄μΌ νλ κ²½μ°.
- μν λ‘μ§μ μ€μ μ§μ€ννκ³ λλ²κΉ μ λ μ½κ² λ§λ€κ³ μΆμ κ²½μ°.
- λμ€μ μ ν리μΌμ΄μ μ νμ₯νκ±°λ μν κ΄λ¦¬λ₯Ό 리ν©ν λ§ν κ²μΌλ‘ μμλλ κ²½μ°.
- λ€μκ³Ό κ°μ κ²½μ°
useStateλ₯Ό μ ννμΈμ: - μνκ° κ°λ¨νκ³ λ¨μΌ κ°μ λνλ΄λ κ²½μ°.
- μν μ λ°μ΄νΈκ° κ°λ¨νλ©° μ΄μ μνμ μμ‘΄νμ§ μλ κ²½μ°.
- μν μ λ°μ΄νΈ μκ° μλμ μΌλ‘ μ μ κ²½μ°.
- κΈ°λ³Έ μν κ΄λ¦¬λ₯Ό μν λΉ λ₯΄κ³ μ¬μ΄ μ루μ μ μνλ κ²½μ°.
μΌλ°μ μΌλ‘ useState μ
λ°μ΄νΈ ν¨μ λ΄μμ 볡μ‘ν λ‘μ§μ μμ±νκ³ μλ€λ©΄, useReducerκ° λ μ ν©ν μ μλ€λ μ’μ μ§μ‘°μ
λλ€. useReducer ν
μ 볡μ‘ν μν μ ν μν©μμ λ κΉλνκ³ μ μ§λ³΄μνκΈ° μ¬μ΄ μ½λλ₯Ό μμ±νλ κ²½μ°κ° λ§μ΅λλ€. λν μν μ
λ°μ΄νΈλ₯Ό μννλ μΌκ΄λ λ©μ»€λμ¦μ μ 곡νλ―λ‘ μ½λμ λ¨μ ν
μ€νΈλ₯Ό λ μ½κ² λ§λλ λ° λμμ΄ λ μ μμ΅λλ€.
λͺ¨λ² μ¬λ‘ λ° κ³ λ € μ¬ν
useReducerλ₯Ό μ΅λν νμ©νλ €λ©΄ λ€μ λͺ¨λ² μ¬λ‘ λ° κ³ λ € μ¬νμ μΌλμ λμμμ€:
- μ‘μ ꡬμ±: μ€νλ₯Ό λ°©μ§νκ³ μ½λλ₯Ό λ μ μ§λ³΄μνκΈ° μ½κ² λ§λ€λ €λ©΄ μ‘μ μ νμ μμ(μ: `const INCREMENT = 'increment';`)λ‘ μ μνμμμ€. μ‘μ μμ±μ μΊ‘μννκΈ° μν΄ μ‘μ μμ±μ ν¨ν΄μ μ¬μ©νλ κ²μ κ³ λ €νμμμ€.
- νμ κ²μ¬: λ ν° νλ‘μ νΈμ κ²½μ°, μν, μ‘μ λ° λ¦¬λμ ν¨μμ νμ μ μ§μ νκΈ° μν΄ TypeScript μ¬μ©μ κ³ λ €νμμμ€. μ΄λ μ€λ₯λ₯Ό λ°©μ§νκ³ μ½λ κ°λ μ± λ° μ μ§λ³΄μμ±μ ν₯μμν€λ λ° λμμ΄ λ κ²μ λλ€.
- ν μ€ν : 리λμ ν¨μμ λν λ¨μ ν μ€νΈλ₯Ό μμ±νμ¬ μ¬λ°λ₯΄κ² μλνκ³ λ€μν μ‘μ μλ리μ€λ₯Ό μ²λ¦¬νλμ§ νμΈνμμμ€. μ΄λ μν μ λ°μ΄νΈκ° μμΈ‘ κ°λ₯νκ³ μ λ’°ν μ μλμ§ νμΈνλ λ° μ€μν©λλ€.
- μ±λ₯ λͺ¨λν°λ§: λΈλΌμ°μ κ°λ° λꡬ(μ: React DevTools) λλ μ±λ₯ λͺ¨λν°λ§ λꡬλ₯Ό μ¬μ©νμ¬ μ»΄ν¬λνΈμ μ±λ₯μ μΆμ νκ³ μν μ λ°μ΄νΈμ κ΄λ ¨λ λ³λͺ© νμμ μλ³νμμμ€.
- μν νν μ€κ³: λΆνμν μ€μ²©μ΄λ 볡μ‘μ±μ νΌνκΈ° μν΄ μν ννλ₯Ό μ μ€νκ² μ€κ³νμμμ€. μ ꡬ쑰νλ μνλ μ΄ν΄νκ³ κ΄λ¦¬νκΈ° λ μ¬μΈ κ²μ λλ€.
- λ¬Έμν: νΉν νμ νλ‘μ νΈμμ 리λμ ν¨μ λ° μ‘μ μ νμ λͺ ννκ² λ¬Έμννμμμ€. μ΄λ λ€λ₯Έ κ°λ°μκ° μ½λλ₯Ό μ΄ν΄νκ³ μ μ§λ³΄μνκΈ° λ μ½κ² λ§λλ λ° λμμ΄ λ κ²μ λλ€.
- λμ κ³ λ € (Redux, Zustand λ±): κ·Ήλλ‘ λ³΅μ‘ν μν μꡬ μ¬νμ κ°μ§ λ§€μ° ν° μ ν리μΌμ΄μ
μ κ²½μ° λλ νμ΄ μ΄λ―Έ Reduxμ μ΅μν κ²½μ°, λ ν¬κ΄μ μΈ μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλ κ²μ κ³ λ €ν μ μμ΅λλ€. κ·Έλ¬λ
useReducerμ Context APIλ μΈλΆ λΌμ΄λΈλ¬λ¦¬μ μΆκ° 볡μ‘μ± μμ΄ κ°λ ₯ν μ루μ μ μ 곡ν©λλ€.
κ²°λ‘
Reactμ useReducer ν
μ μ ν리μΌμ΄μ
μμ 볡μ‘ν μνλ₯Ό κ΄λ¦¬νκΈ° μν κ°λ ₯νκ³ μ μ°ν λꡬμ
λλ€. κΈ°λ³Έμ μ΄ν΄νκ³ , κ³ κΈ ν¨ν΄μ λ§μ€ν°νλ©°, μ±λ₯ μ΅μ ν κΈ°μ μ ꡬνν¨μΌλ‘μ¨, λ κ°λ ₯νκ³ μ μ§λ³΄μνκΈ° μ¬μ°λ©° ν¨μ¨μ μΈ React μ»΄ν¬λνΈλ₯Ό ꡬμΆν μ μμ΅λλ€. νλ‘μ νΈμ νμμ λ°λΌ μ κ·Ό λ°©μμ μ‘°μ νλ κ²μ μμ§ λ§μμμ€. 볡μ‘ν μμ κ΄λ¦¬λΆν° μ₯λ°κ΅¬λ ꡬμΆ, μꡬμ μΈ μ€μ μ²λ¦¬κΉμ§, useReducerλ μ μΈκ³ κ°λ°μλ€μ΄ μ κ΅νκ³ μ¬μ©μ μΉνμ μΈ μΈν°νμ΄μ€λ₯Ό λ§λ€ μ μλλ‘ μ§μν©λλ€. React κ°λ°μ μΈκ³μ λ κΉμ΄ νκ³ λ€μλ‘ useReducerλ₯Ό λ§μ€ν°νλ κ²μ΄ λꡬ ν€νΈμμ λ§€μ° κ·μ€ν μμ°μ΄ λ κ²μ
λλ€. μ ν리μΌμ΄μ
μ΄ μκ°μ΄ μ§λλ μ΄ν΄νκΈ° μ½κ³ λ°μ ν μ μλλ‘ νμ μ½λ λͺ
νμ±κ³Ό μ μ§λ³΄μμ±μ μ΅μ°μ μΌλ‘ νμμμ€.