티스토리 뷰
1️⃣ Reduce ❗
reducer는 Store의 문지기’라고 생각하면 된다.
reducer는 이전 상태와 Action을 합쳐, 새로운 state를 만드는 조작을 말한다.
2️⃣ Action ❗
Store 및 Store에 존재하는 State에 직접 접근하기 위해 Action을 꼭 거쳐야 한다.
- Store에 대해 뭔가 하고 싶은 경우엔 Action을 발행한다.
- reducer가 Action의 발생을 감지하면, State가 경신된다.
Action은 기본적으로 {type, payload} 포맷을 갖고 있는 오브젝트가 된다.
다음은 예시 코드이다.
reducers/index.js
import { combineReducers } from 'redux';
import alert from './alert'; // [1]
import auth from './auth'; // [2]
import profile from './profile'; // [3]
import post from './post'; // [4]
export default combineReducers({
alert,
auth,
profile,
post
});
[1]. alert
// reducers/alert.js
import { SET_ALERT, REMOVE_ALERT } from '../actions/types';
const initalState = [];
export default function (state = initalState, action) {
const { type, payload } = action;
switch (type) {
case SET_ALERT:
return [...state, action.payload];
case REMOVE_ALERT:
return state.filter(alert => alert.id !== payload);
default:
return state;
}
}
initailState와 action을 매개변수로 받는다.
action는 type, payload로 구성된다.
// actions/alert.js
import uuid from 'uuid';
import { SET_ALERT, REMOVE_ALERT } from '../actions/types';
export const setAlert = (msg, alertType, timeout = 5000) => dispatch => {
const id = uuid.v4();
dispatch({
type: SET_ALERT,
payload: { msg, alertType, id }
});
setTimeout(() => dispatch({ type: REMOVE_ALERT, payload: id }), timeout);
}
Action에서 type에 따라 dispatch를 통해 나누어 보내준다.
Alert은 다른 Action(ex. post, auth etc)에 알림을 줄 때 활용된다.
[2]. auth
// reducers/auth.js
import {
REGISTER_SUCCESS,
REGISTER_FAIL,
AUTH_ERROR,
USER_LOADED,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT,
ACCOUNT_DELETED
} from "../actions/types";
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: null,
loading: true,
user: null
}
export default function (state = initialState, action) {
const { type, payload } = action;
// Switch 부분 [2-n]
}
initialState에 token, isAuthenticated, loading, user를 넣어준다.
initialState는 각 type에 해당할 때 사용된다.
// actions/auth.js
import axios from 'axios';
import { setAlert } from './alert';
import setAuthToken from '../utils/setAuthToken';
import {
REGISTER_SUCCESS,
REGISTER_FAIL,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT,
CLEAR_PROFILE,
} from "./types";
// reducers에 해당하는 [2-n]
[2-1]. USER_LOADED
// reducers/auth.js
switch (type) {
case USER_LOADED:
return {
...state,
isAuthenticated: true,
loading: false,
user: payload
}
}
// actions/auth.js
export const loadUser = () => async dispatch => {
if (localStorage.token) { // [2-1-1]
setAuthToken(localStorage.token); // header에 x-auth-token : token
}
try {
const res = await axios.get('/api/auth');
dispatch({
type: USER_LOADED,
payload: res.data
});
} catch (error) {
dispatch({
type: AUTH_ERROR
});
}
}
axios는 유저 정보를 가져온다.
[2-1-1]. token을 setAuthToken으로 header에 넣어줄 수 있다.
setAuthToken
import axios from 'axios';
const setAuthToken = (token) => {
if (token) {
axios.defaults.headers.common['x-auth-token'] = token;
} else {
delete axios.defaults.headers.common['x-auth-token'];
}
}
export default setAuthToken;
[2-2]. Success
// reducers/auth.js
switch (type) {
case REGISTER_SUCCESS:
case LOGIN_SUCCESS:
localStorage.setItem('token', payload.token); // [2-2-1]
return {
...state,
...payload,
isAuthenticated: true,
loading: false,
}
}
// actions/auth.js
// Register User
export const register = ({ name, email, password }) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const body = JSON.stringify({ name, email, password });
try {
const res = await axios.post('/api/users', body, config);
dispatch({
type: REGISTER_SUCCESS,
payload: res.data
});
dispatch(loadUser());
} catch (error) {
const errors = error.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: REGISTER_FAIL
})
}
}
// Login User
export const login = ({ email, password }) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
const body = JSON.stringify({ email, password });
try {
const res = await axios.post('/api/auth', body, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(loadUser());
} catch (error) {
const errors = error.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: LOGIN_FAIL
})
}
};
[2-2-1]. localStorage.setItem('token', payload.token);
회원가입, 로그인이 완료하면 token을 initialState에 저장해준다.
[2-3]. Fail
// reducers/auth.js
switch (type) {
case REGISTER_FAIL:
case AUTH_ERROR:
case LOGIN_FAIL:
case LOGOUT:
case ACCOUNT_DELETED:
localStorage.removeItem('token');
return {
...state,
toekn: null,
isAuthenticated: false,
loading: false,
}
default:
return state;
}
// actions/auth.js
// Logout / Clear Profile
export const logout = () => dispatch => {
dispatch({
type: LOGOUT
});
dispatch({
type: CLEAR_PROFILE
});
}
references
'Node.js > react' 카테고리의 다른 글
react-redux Flow (0) | 2020.09.28 |
---|---|
Redux - connect (0) | 2020.09.28 |
Redux - Store (0) | 2020.09.27 |
Middleware와 thunk (0) | 2020.09.27 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- Effective Java
- BOJ
- 이팩티브 자바
- 클린 코드
- kotest
- 디자인패턴
- Spring Boot
- 백준
- 객체지향
- Olympiad
- JPA
- programmers
- 클린 아키텍처
- 코테
- 프로그래머스
- C++
- 알고리즘
- 이펙티브 자바
- Spring
- AWS
- 정규표현식
- Java
- 테라폼
- Kotlin
- kkoon9
- BAEKJOON
- node.js
- 디자인 패턴
- Algorithm
- MSA
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
글 보관함