์ด์ ์ ๋ฆฌ๋์ค์ ๊ดํด ์ ๋ฆฌํ ์ ์ด ์๋ค. ๋๋ฌด ๊ฐ์ํ๊ฒ ์ ๋ฆฌํด์ ์ด๋ฒ์ ํ๋ก์ ํธ ์์ ์ ๊ณต๋ถํ ๊ฒธ ๋ค์ ์ ๋ฆฌํด ๋ณธ๋ค.
๋ฆฌ๋์ค๋ ๋ฆฌ์กํธ๋ก ๋ง๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ํ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๊ฒ ๋์์ฃผ๋ ๋๊ตฌ์ด๋ค. (๋ฌผ๋ก ๋ฆฌ์กํธ ๋ฟ๋ง ์๋๋ผ jQuery, Angular ๋ฑ์ ์ฌ์ฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค!) ์ฒ์ ๋ฆฌ๋์ค๋ฅผ ๋ฐฐ์ ์ ๋ ์ ๋ฆฌ๋์ค๋ฅผ ๋ฐฐ์ฐ๊ณ , ์ ์ฉํด์ผํ๋์ง ๋ชฐ๋์ง๋ง ์ฒซ๋ฒ์งธ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ์ ํ์ํ๊ณ , ๋ฆฌ๋์ค๋ฅผ ์ฌ์ฉํ์ ๋ ์ํ๊ด๋ฆฌ๊ฐ ํธ๋ฆฌํ ๊ฒ์ด๋ ๊ฑธ ์ ์คํ ๊นจ๋ฌ์๋ค.
๋ฆฌ์กํธ๊ฐ ๊ฐ์ง๊ณ ์๋ ContextAPI์ useReducer
ํ
์ ์ด์ฉํด ๋ฌผ๋ก ์ํ๊ด๋ฆฌ๋ฅผ ํ ์ ์์ง๋ง ๋ง์ฝ ์์ฑํด์ผ ํ ์์ ์ปดํฌ๋ํธ๊ฐ ํ ๋๊ฐ๊ฐ ์๋๋ผ๋ฉด? ๊ทธ ์์์, ์์์, ์์์, ์์์, ... ์ปดํฌ๋ํธ์๊ฒ ์ํ๋ฅผ ์ ๋ฌํด์ค์ผ ํ๋ค๋ฉด? ๋ง์ฝ ๋ถ๋ชจ-์์ ๊ด๊ณ์ ์ปดํฌ๋ํธ๊ฐ ์๋ ์ ๋ฉ๋ฆฌ ์๋ ํ์ ๊ด๊ณ์ ์ปดํฌ๋ํธ์์ ์ํ๋ฅผ ์ฃผ๊ณ ๋ฐ์์ผํ๋ค๋ฉด? ์์ฃผ ์ง์ฅ์ ๋ง๋ณผ๊ฒ์ด๋ค.. ใ
ใ
ใ
๐
์ํ์ ๋ณํ๊ฐ ํ์ํ ๋ ์ก์
์ด๋ ๊ฐ์ฒด๋ฅผ ๋ฐ์์ํจ๋ค. ์ก์
๊ฐ์ฒด๋ type
ํ๋๋ฅผ ํ์์ ์ผ๋ก ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ฉฐ ๊ทธ ์ธ ๊ฐ๋ค์ ์
๋ง๋๋ก ๋ฃ์ผ๋ฉด ๋๋ค. ์ก์
์์ฑํจ์๋ ๋ง๊ทธ๋๋ก ์ก์
์ ๋ง๋๋ ํจ์์ด๋ฉฐ ์ก์
๊ฐ์ฒด ํํ๋ก ๋ฐํํ๋ค.
export const action = (data) => ({
type: "action_type",
data //data: data(๋ฐ์์จ ํ๋ผ๋ฏธํฐ๊ฐ ๊ฐ์ผ๋ก ๋ค์ด๊ฐ๋ค.)
});
๋ฆฌ๋์๋ ์ํ ๋ณํ๋ฅผ ์ผ์ผํค๋ ํจ์์ด๋ค. ํ์ฌ ์ํ์ ์ ๋ฌ ๋ฐ์ ์ก์
๋๊ฐ์ง์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์์ค๊ณ ๊ทธ ์ก์
์ ์ฐธ๊ณ ํด์ ์๋ก์ด ์ํ๋ฅผ ๋ง๋ค์ด ๋ฐํํ๋ค. switch-case๋ฌธ์ ์ฐ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๊ณ default
์์ state๋ฅผ ๊ทธ๋๋ก ๋ฐํํด์ผ ํ๋ค. ์ฌ๋ฌ ๊ฐ์ ๋ฆฌ๋์๋ฅผ ๋ง๋ค ์ ์๊ณ ์ด๋ฅผ ์ ๋ถ ๋ค ํฉ์ณ ๋ฃจํธ ๋ฆฌํ์๋ผ๊ณ ๋ถ๋ฅธ๋ค.
// ๋ฆฌ๋์ ์์ฑ ์ฝ๋
function reducer(state, action){
switch (action.type) {
case "action1":
return state + 1;
case "action2":
return state - 1;
default:
return state;
}
}
// ๋ฃจํธ ๋ฆฌ๋์๋ก ํฉ์น๋ ์ฝ๋
import { combineReducers } from 'redux';
import reducer1 from './reducer1';
import reducer2 from './reducer2';
const rootReducer = combineReducers({ reducer1, reducer2 });
ํ ์ ํ๋ฆฌ์ผ์ด์ ๋น ํ๋์ ์คํ ์ด๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ ์ด ์คํ ์ด์๋ state์ reducer, ๋ช๊ฐ์ง์ ๋ด์ฅ ํจ์๋ค์ด ์๋ค.
์คํ ์ด์ ๋ด์ฅ ํจ์ ์ค ํ๋์ด๋ค. ์ก์ ์ ๋ฐ์์ํค๊ธฐ ์ํด ์ฌ์ฉํ๋ฉฐ ์ก์ ์ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ๋ค. (๊ฐ์ฒด๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ๋ค๋ ๊ฒ๊ณผ ๋์ผํ ์๋ฏธ์ด๋ค.) ๋์คํจ์น๋ฅผ ํธ์ถํ๋ฉด ์คํ ์ด์์ ๋ฆฌ๋์ ํจ์๋ฅผ ์คํ์์ผ ํด๋น ์ก์ ์ ์ฒ๋ฆฌํ๋ ๋ก์ง์ด ์๋ค๋ฉด ์ก์ ์ ์ฐธ๊ณ ํด ์๋ก์ด ์ํ๋ฅผ ๋ง๋ค์ด์ค๋ค.
ํ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ๊ฐ์ ์คํ ์ด๋ฅผ ๊ฐ์ง ์ ์์ง๋ง ๊ถ์ฅ๋์ง๋ ์๋๋ค.
๋ฆฌ๋์์์ ์ํ๋ฅผ ์๋ก์ด ์ํ๋ฅผ ๋ง๋ค์ด ๋ฐํํ๋ค๊ณ ์ค๋ช
ํ๋๋ฐ, ๊ทธ ์ด์ ๋ ๋ถ๋ณ์ฑ์ ์ ์งํด์ผํ๊ธฐ ๋๋ฌธ์ด๋ค. ๊ทธ๋์ผ ๊ฐ๋ฐ์ ๋๊ตฌ๋ฅผ ํตํด ๋ค๋ก ๋๋ฆด ์๋ ์๊ณ ๋ค์ ์์ผ๋ก ๋๋ฆด ์๋ ์๋ค.
์ํ๊ฐ ๋ฐฐ์ด์ด๋ค โก๏ธ push()
์ฌ์ฉ ์ ๋ ๊ธ์ง! concat
๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ์กด์ ๋ฐฐ์ด์ ์์ ํ์ง ์๊ณ ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ค์ด ๊ต์ฒดํ๋ ๋ฐฉ์์ผ๋ก ์
๋ฐ์ดํธํ๋ค.
์ํ๊ฐ ๊ฐ์ฒด๋ค โก๏ธ ์คํ๋ ๋ ์ฐ์ฐ์๋(...state, )
Object.assign
๊ณผ ๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํด ๊ธฐ์กด์ ๊ฐ์ฒด๋ ๊ฑด๋๋ฆฌ์ง ์๊ณ ์
๋ฐ์ดํธํ๋ค.
๋ฆฌ๋์๋ ์ด์ ์ํ(PrevState)์ ์ก์ ๊ฐ์ฒด๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๋๋ค. ์ด์ ์ ์ํ๋ ์ ๋ ๊ฑด๋๋ฆฌ์ง ์๊ณ ๋ณํ๋ฅผ ์ผ์ผํจ ์๋ก์ด ์ํ๋ฅผ ๋ง๋ค์ด ๋ฐํํด์ผํ๋ค. ๋๊ฐ์ ํ๋ผ๋ฏธํฐ๋ก ํธ์ถ๋ ๋ฆฌ๋์ ํจ์๋ ์ธ์ ๋ ๋๊ฐ์ ๊ฒฐ๊ณผ๊ฐ์ ๋ฐํํด์ผ ํ๋ค.
๊ธฐ์กด์ ๋ฆฌ๋์ค๋ ์ก์ ์ด ๋ฐ์ํ๋ฉด ๋์คํจ์น๋ฅผ ํตํด ์คํ ์ด์๊ฒ ์ํ ๋ณํ๋ฅผ ์๋ ค์ค๋ค. ๋ง์ฝ ์ด๋ค ์ก์ ์ด ๋ฐ์ํ๋์ง ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๊ณ ์ถ๋ค๊ฑฐ๋, ์ก์ ์ ์ทจ์ํ๊ณ ์ถ๊ฑฐ๋, ํน์ ๋ ๋ค๋ฅธ ์ก์ ์ ์คํ์ํค๊ณ ์ถ์ผ๋ฉด? ๋๊ธฐ์ ์ธ ๋ฆฌ๋์ค ํ๋ฆ์์ ๋น๋๊ธฐ ์์ ์ ์คํํด์ผํ ๋ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ฏธ๋ค์จ์ด์ด๋ค.
๋ฑ๋ฑ ์ฌ๋ฌ ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ ๋ ๋ฆฌ๋์ค-๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. ๋ฆฌ๋์ค ๋ฏธ๋ค์จ์ด์ ์ข ๋ฅ๋ redux-logger, redux-thunk, redux-saga, redux-observable, redux-promise-middleware ๋ฑ์ด ์์ง๋ง redux-logger, redux-thunk ๋ถ๋ถ๋ง ์ ๋ฆฌํ๋๋ก ํ๊ฒ ๋ค.
const middleware = store => next => action => {
console.log(action); // ์ก์
์ ์ถ๋ ฅํ๋ค.
const result = next(action); // ๋ค์ ๋ฏธ๋ค์จ์ด(๋๋ ๋ฆฌ๋์)์๊ฒ ์ก์
์ ์ ๋ฌํ๋ค.
return result; // dispatch(action)์ ๊ฒฐ๊ณผ๋ฌผ - default: undefined
}
๋ฏธ๋ค์จ์ด๋ ํจ์๋ฅผ ์ฐ๋ฌ์์ ๋ ๋ฒ ๋ฆฌํดํ๋ ํจ์์ด๋ค. ์ฒซ๋ฒ์งธ store๋ ๋ฆฌ๋์ค ์คํ ์ด ์ธ์คํด์ค์ด๋ค. ๋๋ฒ์งธ next๋ ์ก์ ์ ๋ค์ ๋ฏธ๋ค์จ์ด์๊ฒ ์ ๋ฌํ๋ ํจ์์ด๋ค. ์ธ๋ฒ์งธ action์ ํ์ฌ ์ฒ๋ฆฌํ๊ณ ์๋ ์ก์ ๊ฐ์ฒด์ด๋ค.
import logger from 'redux-logger';
const store = createStore(rootReducer, applyMiddleware(logger));
๋ฆฌ๋์ค ๋ก๊ฑฐ๋ ์ฑ์์ ๋ฐ์ํ๋ ์ก์ ์ ๋ณด๋ฅผ ์ฝ์์ ์ถ๋ ฅํ๋ ๋ฏธ๋ค์จ์ด์ด๋ค. ๋์คํจ์น๋ ์ก์ ์ด ์ด๋ค ์ก์ ์ธ์ง ํ์ธ ํ ์ฝ์์ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๊ณ ์ก์ ์ ์คํ ์ด์ ์ ๋ฌํ๋ค. ์ฌ๋ฌ ๊ฐ์ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ค๋ฉด logger๋ ๋ณดํต ๋งจ ๋ค์ ์ฐ๋ ํธ์ด๋ค.
๋ฆฌ๋์ค ํ ํฌ๋ ๋น๋๊ธฐ ์์ ์ ์ฒ๋ฆฌํ ๋ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ๋ฏธ๋ค์จ์ด๋ค. ์ก์ ๊ฐ์ฒด๊ฐ ์๋ ํจ์๋ฅผ ๋์คํจ์นํ ์ ์๋ค.
const getComments = () => async (dispatch, getState) => {
const id = getState().post.activeId;
dispatch({ type: 'GET_COMMENTS' });
try {
const comments = await api.getComments(id);
dispatch({ type: 'GET_COMMENTS_SUCCESS', id, comments });
} catch (e) {
dispatch({ type: 'GET_COMMENTS_ERROR', error: e });
}
}
์์๋ก ๊ฐ์ ธ์จ ์ฝ๋๋ฅผ ํด์ํด๋ณด๊ฒ ๋ค. getComments
๋ผ๋ thunk ํจ์๋ฅผ ์ ์ํ ์์์ด๋ค. thunk ํจ์๋ dispatch์ getState๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์์จ๋ค. id
์ ํ์ฌ ์ํ์ post์์ activeId ๊ฐ์ ํ ๋นํ๋ค. ๊ทธ๋ฆฌ๊ณ ์์ฒญ์ ์์ํ์์ ์๋ฆฌ๋ GET_COMMENTS
์ก์
์ ๋์คํจ์น์ ๋ด๋๋ค. ๋ง์ฝ ์์ฒญ์ด ์ฑ๊ณตํ๋ค๋ฉด comments
payload๋ฅผ ๋ด๊ณ ์์ฒญ์ด ์ฑ๊ณตํ์์ ์๋ฆฌ๋ GET_COMMENTS_SUCCESS
์ก์
์ ๋์คํจ์น์ ๋ด์ ์คํํ๋ค. ๊ทธ๋ฌ๋ฉด ์ด์ ๋ฆฌ๋์๋ฅผ ํตํด ์ํ๊ฐ ๋ณ๊ฒฝ๋์ด ์์ ๊ฒ์ด๋ค.
import ReduxThunk from 'redux-thunk';
const store = createStore(
rootReducer, applyMiddleware(ReduxThunk)
);
store๋ฅผ ์ ์ํด๋ ๊ณณ์ applyMiddleware๋ฅผ ์ฐ๊ณ ํ๋ผ๋ฏธํฐ๋ก ๋ด์์ค๋ค.
export const increase = () => ({ type: INCREASE });
// getState๋ฅผ ์ฐ์ง ์๋๋ค๋ฉด ๊ตณ์ด ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์์ฌ ํ์ ์์ต๋๋ค.
export const increaseAsync = () => dispatch => {
setTimeout(() => dispatch(increase()), 1000);
};
์ฐธ๊ณ : ๋น๊ฐ์ ๋ฒจ๋กํผํธ ์จ์๋