Redux는 복잡한 애플리케이션에서 상태를 보다 체계적으로 관리할 수 있게 해주는 라이브러리입니다.
Redux
1. 상태 관리의 필요성과 Redux 등장 배경
주요 개념 설명
- 상태 관리의 필요성: React 애플리케이션에서 컴포넌트 간 상태가 공유되어야 할 때 props를 통해 전달하거나 Context API를 사용해 데이터를 전달합니다. 그러나 애플리케이션이 복잡해질수록 상태가 여러 컴포넌트에 걸쳐 복잡하게 얽히게 되어 관리가 어려워질 수 있습니다.
- Redux의 등장 배경: 애플리케이션 상태를 체계적으로 관리하고, 상태 변경 흐름을 명확하게 하기 위해 Redux가 등장했습니다. Redux는 단일 상태 트리로 전체 애플리케이션 상태를 관리하며, 상태 변경이 예측 가능하게끔 합니다.
사용 시나리오
- Redux는 대규모 애플리케이션에서 전역 상태가 필요할 때 사용합니다. 사용자 인증, 데이터 페칭, 다중 페이지 간의 데이터 공유가 필요한 애플리케이션에 적합합니다.
2. Redux의 주요 개념: Action, Reducer, Store
주요 개념 설명
- Action: 상태를 변경하기 위한 '의도'를 표현하는 객체입니다. `type` 필드를 필수로 포함하며, 추가 데이터는 `payload`라는 속성으로 전달됩니다.
- Reducer: 상태의 변화를 정의하는 순수 함수입니다. 현재 상태와 액션을 받아, 변경된 새로운 상태를 반환합니다.
- Store: 애플리케이션의 상태가 저장되는 장소입니다. 모든 상태 변경은 Store를 통해 이루어지며, 전역 상태로 사용됩니다.
사용 시나리오
- Action은 사용자의 입력 이벤트나 네트워크 응답을 통해 트리거됩니다.
- Reducer는 액션에 따라 상태가 변경되도록 정의하며, 상태 변화 로직을 중앙 집중화하여 유지보수성을 높입니다.
- Store는 애플리케이션의 모든 상태를 단일화하여 여러 컴포넌트에서 쉽게 접근하고 수정할 수 있게 합니다.
예시 코드
// Action
const increment = () => ({
type: 'INCREMENT'
});
// Reducer
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
default:
return state;
}
};
// Store
import { createStore } from 'redux';
const store = createStore(counterReducer);
// 상태 구독 및 변경
store.subscribe(() => console.log(store.getState()));
store.dispatch(increment()); // 상태: 1
3. Redux Toolkit 소개 및 사용법
주요 개념 설명
- Redux Toolkit은 Redux 설정을 단순화하고 직관적인 API를 제공합니다. `createSlice`와 같은 기능을 통해 Reducer와 Action을 한 번에 정의하고, `configureStore`를 통해 미들웨어나 Redux DevTools 설정을 쉽게 할 수 있습니다.
사용 시나리오
- Redux Toolkit은 Redux 설정을 빠르고 쉽게 할 수 있도록 해주기 때문에, 새로운 프로젝트에서 Redux를 빠르게 설정해야 할 때 유용합니다.
예시 코드
import { configureStore, createSlice } from '@reduxjs/toolkit';
// Slice 생성
const counterSlice = createSlice({
name: 'counter',
initialState: 0,
reducers: {
increment: state => state + 1,
decrement: state => state - 1
}
});
const { actions, reducer } = counterSlice;
const store = configureStore({ reducer: { counter: reducer } });
store.subscribe(() => console.log(store.getState()));
store.dispatch(actions.increment()); // 상태: 1
store.dispatch(actions.decrement()); // 상태: 0
4. Redux Thunk, 미들웨어 사용법
주요 개념 설명
- 미들웨어: Redux에서 액션이 Reducer에 도달하기 전에 가로채서 다른 작업을 할 수 있도록 도와주는 기능입니다.
- Redux Thunk: 비동기 작업을 처리할 수 있는 미들웨어로, 액션 크리에이터가 일반 객체가 아닌 함수를 반환할 수 있게 합니다. 이를 통해 비동기 API 호출을 관리할 수 있습니다.
사용 시나리오
- Redux Thunk는 비동기 데이터 페칭이나 API 호출을 수행할 때 유용합니다. 예를 들어, 서버에서 데이터를 받아와 Redux 상태에 저장해야 할 때 사용됩니다.
예시 코드
import { configureStore, createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import thunk from 'redux-thunk';
// Thunk 생성
export const fetchTodos = createAsyncThunk('todos/fetch', async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/todos');
return response.json();
});
// Slice 생성
const todosSlice = createSlice({
name: 'todos',
initialState: { items: [], status: 'idle' },
reducers: {},
extraReducers: builder => {
builder
.addCase(fetchTodos.pending, state => { state.status = 'loading'; })
.addCase(fetchTodos.fulfilled, (state, action) => {
state.status = 'succeeded';
state.items = action.payload;
})
.addCase(fetchTodos.rejected, state => { state.status = 'failed'; });
}
});
const store = configureStore({ reducer: { todos: todosSlice.reducer }, middleware: [thunk] });
store.dispatch(fetchTodos());
5. 실습 예제: Todo 리스트를 사용한 Redux 상태 관리 구현
주요 개념 설명
이 실습에서는 Redux를 사용해 간단한 Todo 리스트 애플리케이션을 만들며, Redux의 기본적인 상태 관리 개념을 실습해봅니다.
예시 코드
1. Redux 설정
import { configureStore, createSlice } from '@reduxjs/toolkit';
const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
addTodo: (state, action) => {
state.push({ id: Date.now(), text: action.payload, completed: false });
},
toggleTodo: (state, action) => {
const todo = state.find(todo => todo.id === action.payload);
if (todo) todo.completed = !todo.completed;
}
}
});
const { actions, reducer } = todosSlice;
const store = configureStore({ reducer: { todos: reducer } });
export const { addTodo, toggleTodo } = actions;
export default store;
2. 컴포넌트 코드
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addTodo, toggleTodo } from './store';
function TodoApp() {
const [text, setText] = useState('');
const dispatch = useDispatch();
const todos = useSelector(state => state.todos);
const handleAddTodo = () => {
dispatch(addTodo(text));
setText('');
};
return (
<div>
<h1>Todo List</h1>
<input
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Add a new todo"
/>
<button onClick={handleAddTodo}>Add Todo</button>
<ul>
{todos.map(todo => (
<li
key={todo.id}
onClick={() => dispatch(toggleTodo(todo.id))}
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}
export default TodoApp;
'REACT' 카테고리의 다른 글
REACT Supabase (0) | 2024.11.05 |
---|---|
React Router (0) | 2024.11.05 |
REACT_숙련 (0) | 2024.11.05 |
REACT HOOK (0) | 2024.11.05 |
REACT의 기본구조와 스타일링 (0) | 2024.11.05 |