Javascipt ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. Redux๋ฅผ ์ฌ์ฉํ๋ฉด store๋ผ๋ ๋ฐ์ดํฐ ๊ณต๊ฐ์ ๋ง๋ ํ ํด๋น ๊ณต๊ฐ ์์์ ๋ฐ์ดํฐ์ ์ํ๋ฅผ ๊ด๋ฆฌํ ์ ์๋ค. Redux์๋ store, action, reducer๋ผ๋ ์ธ๊ฐ์ง ๊ฐ๋ ์ด ์กด์ฌํฉ๋๋ค.
Redux ์ค์น ๋ฐฉ๋ฒ
npm install redux
npm install react-redux
npm install redux-actions
npm install redux-devtools-extenstion
npm install immer
Redux ์ํ ๊ด๋ฆฌ ์์
1. ์ํ๊ฐ ๋ณ๊ฒฝ๋์ด์ผ ํ๋ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด, ๋ณ๊ฒฝ๋ ์ํ์ ๋ํ ์ ๋ณด๊ฐ ๋ด๊ธด Aciton ๊ฐ์ฒด๊ฐ ์์ฑ๋ฉ๋๋ค.
2. ์ด Action ๊ฐ์ฒด๋ Dispatch ํจ์์ ์ธ์๋ก ์ ๋ฌ๋ฉ๋๋ค.
3. Dispatch ํจ์๋ Action ๊ฐ์ฒด๋ฅผ Reducer ํจ์๋ก ์ ๋ฌํด์ค๋๋ค.
4. Reducer ํจ์๋ Action ๊ฐ์ฒด์ ๊ฐ์ ํ์ธํ๊ณ , ๊ทธ ๊ฐ์ ๋ฐ๋ผ ์ ์ญ ์ํ ์ ์ฅ์ store์ ์ํ๋ฅผ ๋ณ๊ฒฝํฉ๋๋ค.
5. ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด, React๋ ํ๋ฉด์ ๋ค์ ๋ ๋๋ง ํฉ๋๋ค.
์ํ๊ฐ ๊ด๋ฆฌ๋๋ ์ค์ง ํ๋๋ฟ์ธ ์ ์ฅ์์ ์ญํ ์ ํฉ๋๋ค.
import { createStore } from 'redux';
const store = createStore(rootReducer);
Dispatch์๊ฒ์ ์ ๋ฌ๋ฐ์ Action ๊ฐ์ฒด์ type ๊ฐ์ ๋ฐ๋ผ์ ์ํ๋ฅผ ๋ณ๊ฒฝ์ํค๋ ํจ์์ ๋๋ค. Reducer๋ ์์ํจ์์ฌ์ผ ํฉ๋๋ค. ์ธ๋ถ ์์ธ์ผ๋ก ์ธํด ๊ธฐ๋ํ ๊ฐ์ด ์๋ ์๋ฑํ ๊ฐ์ผ๋ก ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ ์ผ์ด ์์ด์ผํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
const count = 1
// Reducer๋ฅผ ์์ฑํ ๋์๋ ์ด๊ธฐ ์ํ๋ฅผ ์ธ์๋ก ์๊ตฌํฉ๋๋ค.
const counterReducer = (state = count, action) => {
// Action ๊ฐ์ฒด์ type ๊ฐ์ ๋ฐ๋ผ ๋ถ๊ธฐํ๋ switch ์กฐ๊ฑด๋ฌธ์
๋๋ค.
switch (action.type) {
//action === 'INCREASE'์ผ ๊ฒฝ์ฐ
case 'INCREASE':
return state + 1
// action === 'DECREASE'์ผ ๊ฒฝ์ฐ
case 'DECREASE':
return state - 1
// action === 'SET_NUMBER'์ผ ๊ฒฝ์ฐ
case 'SET_NUMBER':
return action.payload
// ํด๋น ๋๋ ๊ฒฝ์ฐ๊ฐ ์์ ๋ ๊ธฐ์กด ์ํ๋ฅผ ๊ทธ๋๋ก ๋ฆฌํด
default:
return state;
}
}
// Reducer๊ฐ ๋ฆฌํดํ๋ ๊ฐ์ด ์๋ก์ด ์ํ๊ฐ ๋ฉ๋๋ค.
combineReducers ๋ฉ์๋
์ฌ๋ฌ๊ฐ์ reducer๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ. Redux์ combineReducers ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ํ๋์ Reducer๋ก ํฉ์ณ์ค ์ ์์ต๋๋ค.
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
counterReducer,
anyReducer,
...
});
์ด๋ค ์ก์ ์ ์ทจํ ๊ฒ์ธ์ง ์ ์ํด ๋์ ๊ฐ์ฒด์ ๋๋ค.
// payload๊ฐ ํ์ ์๋ ๊ฒฝ์ฐ
const increase = () => {
return {
type: 'INCREASE'
}
}
// payload๊ฐ ํ์ํ ๊ฒฝ์ฐ
const setNumber = (num) => {
return {
type: 'SET_NUMBER',
payload: num
}
}
Reducer๋ก Action์ ์ ๋ฌํด์ฃผ๋ ํจ์์ ๋๋ค. Dispatch์ ์ ๋ฌ์ธ์๋ก Action ๊ฐ์ฒด๊ฐ ์ ๋ฌ๋ฉ๋๋ค.
// Action ๊ฐ์ฒด๋ฅผ ์ง์ ์์ฑํ๋ ๊ฒฝ์ฐ
dispatch( { type: 'INCREASE' } );
dispatch( { type: 'SET_NUMBER', payload: 5 } );
// ์ก์
์์ฑ์(Action Creator)๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
dispatch( increase() );
dispatch( setNumber(5) );
React์์ Redux๋ฅผ ์ฌ์ฉํด ์ํ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํด์ Redux ๋ฟ๋ง์๋๋ผ React์ Redux๋ฅผ ์ฐ๊ฒฐํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐ๋ก ์ค์นํด์ฃผ์ด์ผ ํฉ๋๋ค.
React-Redux์์ Redux๋ฅผ ์ฌ์ฉํ ๋ ํ์ฉํ ์ ์๋ Hooks ๋ฉ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค. ๊ทธ ์ค์์ ํฌ๊ฒ useSelector(), useDispatch() ์ด ๋ ๊ฐ์ง์ ๋ฉ์๋๋ฅผ ๊ธฐ์ตํ๋ฉด ๋ฉ๋๋ค.
useDispatch()
Action ๊ฐ์ฒด๋ฅผ Reducer๋ก ์ ๋ฌํด ์ฃผ๋ Dispatch ํจ์๋ฅผ ๋ฐํํ๋ ๋ฉ์๋์ ๋๋ค.
import { useDispatch } from 'react-redux'
const dispatch = useDispatch()
dispatch( increase() )
console.log(counter) // 2
dispatch( setNumber(5) )
console.log(counter) // 5
useSelector()
์ปดํฌ๋ํธ์ state๋ฅผ ์ฐ๊ฒฐํ์ฌ Redux์ state์ ์ ๊ทผํ ์ ์๊ฒ ํด์ฃผ๋ ๋ฉ์๋์ ๋๋ค.
// Redux Hooks ๋ฉ์๋๋ 'redux'๊ฐ ์๋๋ผ 'react-redux'์์ ๋ถ๋ฌ์ต๋๋ค.
import { useSelector } from 'react-redux'
const counter = useSelector(state => state)
console.log(counter) // 1
redux-actions ํจํค์ง์์ ์ ๊ณต๋๋ createAction๊ณผ handleActions ํจ์๋ฅผ ์ด์ฉํ๋ฉด redux์์ ๋ณด๋ค ์ฝ๊ฒ action๋ค์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
createAction
์ด ํจ์๋ฅผ ์ด์ฉํ๋ฉด action ์์ฑ์ ์๋ํ ํ ์ ์์ต๋๋ค. createAction ํจ์์ ์ธ์๊ฐ์ผ๋ก type ๋ด์ฉ์ ์ ๋ฌํด์ฃผ๋ฉด ์ ๋ฌ๋ฐ์ type์ ๊ฐ์ง action ๊ฐ์ฒด๋ฅผ ์๋์ผ๋ก ์์ฑํด์ค๋๋ค. ๋ํ createAction ํจ์๋ก ๋ง๋ action ์์ฑ ํจ์๋ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌ๋ฐ์ ๊ฐ์ action์ payload ๊ฐ์ผ๋ก ์ค์ ํด์ค๋๋ค.
handleActions
reducer์์ action์ type์ ๋ฐ๋ผ ๋ค๋ฅธ ์์ ์ ํ๊ธฐ ์ํด์ switch๋ฌธ์ ์ฌ์ฉํ์๋ค. ํ์ง๋ง switch๋ฌธ์ ์ฌ์ฉํ๋ ๋ฐฉ์์ scope๊ฐ reducer ํจ์๋ก ์ค์ ๋๋ค๋ ๋จ์ ์ด ์์ต๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์๋ก ๋ค๋ฅธ case์์ let์ด๋ const๋ฅผ ํตํด ๋ณ์๋ฅผ ์ ์ธํ๋ ค๊ณ ํ๋ฉด ๊ฐ์ ์ด๋ฆ์ด ์ค์ฒฉ๋ ์์ ์๋ฌ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค. ํ์ง๋ง handleActions ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
import { createAction, handleActions } from 'redux-actions';
const SAMPLE_ACTION = 'auth/SAMPLE_ACTION';
export const sampleAction = createAction(SAMPLE_ACTION);
const initialState = {};
const auth = handleActions(
{
[SAMPLE_ACTION] : (state, action) => state,
},
initialState,
);
export default auth;
immer๋ React์์ ๋ถ๋ณ์ฑ์ ์ ์งํ๋ ์ฝ๋๋ฅผ ์ฝ๊ฒ ์์ฑํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. React ์ปดํฌ๋ํธ์์ ์ํ๋ฅผ ์ ๋ฐ์ดํธ ํ ๋ ๋ถ๋ณ์ฑ์ ์งํค๋ ๊ฒ์ ๋งค์ฐ ์ค์ํ ์ผ์ ๋๋ค. ๋ถ๋ณ์ฑ์ ์งํค์ง ์์ผ๋ฉด ๊ฐ์ฒด ๋ด๋ถ์ ๊ฐ์ด ์๋ก์์ ธ๋ ๋ฐ๋ ๊ฒ์ ๊ฐ์งํ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
1. Single source of truth
๋์ผํ ๋ฐ์ดํฐ๋ ํญ์ ๊ฐ์ ๊ณณ์์ ๊ฐ์ง๊ณ ์์ผ ํ๋ค๋ ์๋ฏธ์ ๋๋ค. ์ฆ, Redux์๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ Store๋ผ๋ ๋จ ํ๋๋ฟ์ธ ๊ณต๊ฐ์ด ์์๊ณผ ์ฐ๊ฒฐ์ด ๋๋ ์์น์ ๋๋ค.
2. State is read-only
์ํ๋ ์ฝ๊ธฐ ์ ์ฉ์ด๋ผ๋ ๋ป์ผ๋ก, React์์ ์ํ๊ฐฑ์ ํจ์๋ก๋ง ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์์๋ ๊ฒ์ฒ๋ผ, Redux์ ์ํ๋ ์ง์ ๋ณ๊ฒฝํ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ฆ, Action ๊ฐ์ฒด๊ฐ ์์ด์ผ๋ง ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์์๊ณผ ์ฐ๊ฒฐ๋๋ ์์น์ ๋๋ค.
3. Changes are made with pure functions
๋ณ๊ฒฝ์ ์์ํจ์๋ก๋ง ๊ฐ๋ฅํ๋ค๋ ๋ป์ผ๋ก, ์ํ๊ฐ ์๋ฑํ ๊ฐ์ผ๋ก ๋ณ๊ฒฝ๋๋ ์ผ์ด ์๋๋ก ์์ํจ์๋ก ์์ฑ๋์ด์ผํ๋ Reducer์ ์ฐ๊ฒฐ๋๋ ์์น์ ๋๋ค.
์ฐธ๊ณ ํ ์๋ฃ ์ถ์ฒ
https://bitkunst.tistory.com/entry/React-react-redux
https://bitkunst.tistory.com/entry/Redux-redux-actions