누구 알려주려고 쓰는 튜토리얼 아님. 개인 기록용. (John Ahn 님의 따라하며 배우는 노드, 리액트 강의를 보며 작성하였음)
1. Redux 라이브러리 설치
Redux를 쓰려면 라이브러리 다운로드를 해야 한다.
npm install redux react-redux redux-promise redux-thunk --save
redux-promise와 redux-thunk는 action이 객체가 아니라 promise, function이어도 dispatch할 수 있게 해주는 라이브러리이다.
2. index.js 수정
index.js에 아래 내용을 추가한다.
import { Provider } from 'react-redux';
import { applyMiddleware, createStore } from 'redux';
import promiseMiddleware from 'redux-promise';
import ReduxThunk from 'redux-thunk';
import Reducer from './_reducers/index';
const createStoreWithMiddleware = applyMiddleware(promiseMiddleware, ReduxThunk)(createStore)
// 아래는 냅다 추가하지 말고 Provider 태그 이하의 것들만 추가하면 된다.
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider
store={createStoreWithMiddleware(Reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
)}>
<App />
</Provider>
);
3. action, reducer 폴더 및 파일 만들기
src 폴더 내에 '_reducers' 폴더를 만들고, 'index.js'와 'user_reducer.js' 파일을 만든다. index.js 내용은 이렇게 채워준다. user_reducer.js 파일은 6번에서 채워줄 것이다.
_reducers/index.js
import { combineReducers } from "redux";
import user from './user_reducer';
const rootReducer = combineReducers({
user,
})
export default rootReducer;
4. Login을 위한 정보 요청 작업 Dispatch
Login을 하기 위해 email, password를 쓴 다음 '로그인' 버튼을 눌렀을 때, 서버에게 정보를 요청하는 작업을 대충 이런 식으로 짤 수 있다.
LoginPage.js
import { useDispatch } from 'react-redux';
import { loginUser } from '../../../_actions/user_action';
// '로그인' 버튼을 눌렀을 때 처리할 일들
const onSubmitHandler = (event) => {
event.preventDefault(); // 로그인 버튼이 눌릴 때마다 refresh가 일어나는데,
// refresh해도 아래 코드들이 진행되게 해줌
let body = {
email: email,
password: password
}
dispatch(loginUser(body)) // 서버에 로그인을 요청하는 작업을 dispatch
/* Redux를 안쓰는 경우
axios.post('/api/users/login', body)
.then(response => response.data) // backend에서 정한 login route로 body를 보냄
*/
}
src 폴더 내에 action을 위한 폴더 '_actions'를 만들고, 'user_action.js' 파일을 만든다.
_actions/user_action.js
import axios from 'axios';
export function loginUser(dataToSubmit) {
const request = axios.post('/api/users/login', dataToSubmit)
.then(response => response.data) //request에 받아온 data를 저장함
// reducer로 이 action을 넘겨줌
return {
type: "LOGIN_USER",
payload: request
}
}
5. Action type 관리를 위한 파일 만들기
_actions 폴더 내에 types.js 파일을 만든다. action이 지금은 하나지만, 나중에 엄청 많아질 수 있고, 그럼 action type도 많아질 수 있다. 관리하기 좋게 types.js 파일 안에서만 type을 만들기로 하고, 다른 곳에서는 요 types.js를 import해서 쓰도록 한다.
_actions/types.js
// type은 여기에서만 지정할 수 있도록, action type 관리하는 파일
export const LOGIN_USER = "login_user";
user_action 파일을 아래와 같이 수정한다.
_actions/user_action.js
import axios from 'axios';
import { LOGIN_USER } from './types' // types.js import
export function loginUser(dataToSubmit) {
const request = axios.post('/api/users/login', dataToSubmit)
.then(response => response.data)
// action type을 아래와 같이 바꿔줌
return {
type: LOGIN_USER,
payload: request
}
}
6. Reducer 만들기
_reducer/user_reducer.js
import { LOGIN_USER } from '../_actions/types';
export default function (state = {}, action) {
// type이 아주 많아질 수 있으므로 switch를 써줌
switch (action.type) {
case LOGIN_USER:
return { ...state, loginSuccess: action.payload }
default:
return state;
}
}
7. Login page에서 응답 처리하기
6번 reducer에서 loginSuccess를 받아서 만약 로그인에 성공했다면 자동으로 home으로 돌려보내고, 실패했다면 에러창을 띄워주도록 한다. 그러기 위해서 useNavigate를 import하고, 컴포넌트 내에 navigate 변수를 만든다.
import { useNavigate } from 'react-router-dom';
// 컴포넌트 또는 함수 내에 navigate 변수 선언
let navigate = useNavigate();
그리고 dispatch 부분을 아래와 같이 수정한다.
dispatch(loginUser(body))
.then(response => {
if (response.payload.loginSuccess) {
navigate('/');
} else {
alert('Error');
}
})
8. 테스트
Chrome 확장 프로그램 "Redux DevTools"를 사용해 테스트했다.
아직 회원가입 기능을 안 만들었기 때문에, 이미 DB에 있는 email과 password를 입력하고 로그인 버튼을 눌러준다. 아래는 정상적으로 작동했을 때 Redux DevTools를 사용하면 볼 수 있는 화면이다. Test 결과는 아래와 같다.
import reducers from '../../reducers';
test('reducers', () => {
let state;
state = reducers({user:{}}, {type:'login_user',payload:{loginSuccess:true,userId:'631f4731e0fdf6a6262fa554'}});
expect(state).toEqual({user:{loginSuccess:{loginSuccess:true,userId:'631f4731e0fdf6a6262fa554'}}});
});

4번에서 action을 만든 것과 같이 type과 payload 형태로 되어있고, payload는 request에 대한 response.data로 되어있다.

Reducer로 state가 위와 같이 바뀌었음을 확인할 수 있다.
'Frontend > React' 카테고리의 다른 글
| 리액트의 이벤트 처리 방식 까보기 (0) | 2025.03.11 |
|---|---|
| useState의 setState에 함수 넣기 (Functional Update) (0) | 2023.08.17 |
| [react] 달력 만들기 01 (0) | 2023.01.31 |
| [HOC] about HOC(Higher Order Component) (0) | 2022.09.13 |
| [Redux Tutorial] about Redux (0) | 2022.09.13 |