Redux
2025. 4. 1. 00:41ㆍFrameworks/React
Redux
Redux는 JavaScript 애플리케이션을 위한 예측 가능한 상태 컨테이너로, React에 국한되지 않지만 React와 함께 가장 많이 사용됩니다.
Redux의 핵심 원칙
- 단일 진실 소스(Single Source of Truth): 애플리케이션의 모든 상태는 하나의 스토어(store)에 저장
- 상태는 읽기 전용(State is Read-Only): 상태를 변경하는 유일한 방법은 액션(action)을 dispatch하는 것
- 변경은 순수 함수로 작성(Changes are Made with Pure Functions): 리듀서(reducer)는 이전 상태와 액션을 받아 다음 상태를 반환하는 순수 함수
Redux의 주요 개념
- 액션(Action): 어떤 일이 일어났는지 설명하는 객체
- 리듀서(Reducer): 이전 상태와 액션에 따라 새 상태를 계산하는 함수
- 스토어(Store): 애플리케이션의 상태를 보관하는 객체
- 디스패치(Dispatch): 액션을 스토어에 보내는 함수
- 구독(Subscribe): 상태 변화를 감지하는 메커니즘
Redux 설치
npm install redux react-redux
또는
yarn add redux react-redux
Redux 사용 방법
1. 액션 타입과 액션 생성자 정의
// actions/userActions.js
// 액션 타입
export const LOGIN = 'LOGIN';
export const LOGOUT = 'LOGOUT';
// 액션 생성자
export const login = (userData) => ({
type: LOGIN,
payload: userData
});
export const logout = () => ({
type: LOGOUT
});
2. 리듀서 작성
// reducers/userReducer.js
import { LOGIN, LOGOUT } from '../actions/userActions';
const initialState = {
user: null,
isAuthenticated: false
};
function userReducer(state = initialState, action) {
switch (action.type) {
case LOGIN:
return {
...state,
user: action.payload,
isAuthenticated: true
};
case LOGOUT:
return {
...state,
user: null,
isAuthenticated: false
};
default:
return state;
}
}
export default userReducer;
3. 루트 리듀서 생성 (여러 리듀서를 결합)
// reducers/index.js
import { combineReducers } from 'redux';
import userReducer from './userReducer';
import postsReducer from './postsReducer';
const rootReducer = combineReducers({
user: userReducer,
posts: postsReducer
});
export default rootReducer;
4. 스토어 생성
// store.js
import { createStore } from 'redux';
import rootReducer from './reducers';
const store = createStore(
rootReducer,
// Redux DevTools Extension 사용 설정 (선택 사항)
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store;
5. Provider로 애플리케이션 감싸기
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);
6. 컴포넌트에서 Redux 상태 사용
// components/LoginPage.js
import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { login } from '../actions/userActions';
function LoginPage() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
// Redux 상태 접근
const { user, isAuthenticated } = useSelector(state => state.user);
// 디스패치 함수 가져오기
const dispatch = useDispatch();
const handleSubmit = (e) => {
e.preventDefault();
// 액션 디스패치
dispatch(login({ username }));
};
if (isAuthenticated) {
return <p>이미 로그인되었습니다, {user.username}님!</p>;
}
return (
<form onSubmit={handleSubmit}>
<h2>로그인</h2>
<input
type="text"
placeholder="사용자명"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
placeholder="비밀번호"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">로그인</button>
</form>
);
}
export default LoginPage;
// components/Dashboard.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { logout } from '../actions/userActions';
function Dashboard() {
const { user, isAuthenticated } = useSelector(state => state.user);
const dispatch = useDispatch();
if (!isAuthenticated) {
return <p>대시보드를 보려면 로그인하세요.</p>;
}
return (
<div>
<h2>대시보드</h2>
<p>안녕하세요, {user.username}님!</p>
<button onClick={() => dispatch(logout())}>로그아웃</button>
</div>
);
}
export default Dashboard;
Redux 미들웨어
미들웨어는 Redux의 기능을 확장하는 방법으로, 주로 비동기 작업이나 로깅 등에 사용됩니다. 가장 많이 사용되는 Redux 미들웨어는 다음과 같습니다:
- redux-thunk: 액션 생성자가 함수를 반환할 수 있게 해주어 비동기 작업 처리
- redux-saga: 복잡한 비동기 흐름을 더 쉽게 관리
- redux-logger: 액션과 상태 변화를 콘솔에 기록
redux-thunk 예제
npm install redux-thunk
// store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
export default store;
// actions/userActions.js
export const LOGIN_REQUEST = 'LOGIN_REQUEST';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_FAILURE = 'LOGIN_FAILURE';
// 비동기 액션 생성자
export const loginUser = (credentials) => {
return async (dispatch) => {
dispatch({ type: LOGIN_REQUEST });
try {
// API 호출
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credentials)
});
if (!response.ok) {
throw new Error('로그인 실패');
}
const userData = await response.json();
dispatch({
type: LOGIN_SUCCESS,
payload: userData
});
} catch (error) {
dispatch({
type: LOGIN_FAILURE,
payload: error.message
});
}
};
};
'Frameworks > React' 카테고리의 다른 글
Context API vs Redux (0) | 2025.04.01 |
---|---|
Redux Toolkit (0) | 2025.04.01 |
React 상태 관리 (0) | 2025.04.01 |
복잡한 라우팅 구성 예제 (0) | 2025.04.01 |
React Router의 주요 기능 상세 설명 (0) | 2025.04.01 |