κ°μΈ 곡λΆλ₯Ό μν΄ μμ±νμ΅λλ€
μλ°μ€ν¬λ¦½νΈλ₯Ό μν μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬, 리λμ€π 리μ‘νΈλ₯Ό μ¬μ©νλ λ§μ νλ‘μ νΈμμ 리λμ€λ κ°μ΄ μ¬μ©νλλ°, κ·Έ μ΄μ λ
- μ»΄ν¬λνΈ μ½λμ μν κ΄λ¦¬ μ½λμ λΆλ¦¬κ° κ°λ₯νκ³
- SSRμ λ°μ΄ν° μ λ¬μ΄ κ°νΈνλ€
- 리μ‘νΈ μ»¨ν μ€νΈλ³΄λ€ ν¨μ¨μ μΈ λ λλ§μ΄ κ°λ₯νλ€
- λ―Έλ€μ¨μ΄λ₯Ό νμ©ν λ€μν κΈ°λ₯ μΆκ°λ κ°λ₯νλ€
- κ°λ ₯ν λ―Έλ€μ¨μ΄ λΌμ΄λΈλ¬λ¦¬ (ex. redux-saga)
- λ‘컬 μ€ν 리μ§μ λ°μ΄ν° μ μ₯νκ³ λΆλ¬μ€λ μ½λλ₯Ό μ½κ² μμ±ν μ μλ€
μ΄λ° μ΄μ λ‘ κ³΅λΆν react-reduxμ λν΄ μ 리ν΄λ³Έλ€.
리λμ€λ‘ μν κ΄λ¦¬νκΈ°
리λμ€ μ¬μ© μ λ°λΌμΌ ν μΈ κ°μ§ μμΉ
1. μ 체 μνκ°μ νλμ store
κ°μ²΄μ μ μ₯νλ€
μ 체 μνκ°μ΄ νλμ μλ°μ€ν¬λ¦½νΈ κ°μ²΄λ‘ ννλκΈ° λλ¬Έμ νμ©λκ° λμμ§λ€. 리λμ€λ₯Ό μ¬μ©νλ©΄
- νλμ κ°μ²΄λ₯Ό μ§λ ¬ν(serialize)ν΄μ μλ²μ ν΄λΌμ΄μΈνΈκ° νλ‘κ·Έλ¨ μ 체 μνκ°μ μλ‘ μ£Όκ³ λ°μ μ μκ³
- νλ‘κ·Έλ¨μ΄ νΉμ ν μνμ μμ λ λ°μνλ λ²κ·Έλ₯Ό νμΈνκΈ° μν΄ κ·Έ μνκ°μ μ μ₯ν ν λ°λ³΅ν΄μ μ¬νν μ μλ€
- μ΅κ·Όμ μνκ°μ λ²λ¦¬μ§ μκ³ μ μ₯ν΄ λμΌλ©΄ μ€ν μ·¨μ(undo)μ λ€μ μ€ν(redo) κΈ°λ₯μ μ½κ² ꡬνν μ μλ€
2. μνκ°μ λΆλ³ κ°μ²΄μ΄λ€
μνκ°μ μ€μ§ μ‘μ κ°μ²΄μ μν΄μλ§ λ³κ²½λμ΄μΌ νλ€
const incrementAction = {
type: "INCREMENT", // --------------(1)
amount: 123, // --------------(2)
};
store.dispatch(incrementAction); // --(3)
incrementAction
λΌλ μ΄λ¦μ μ‘μ
κ°μ²΄λ₯Ό μ΄ν΄λ³΄λ©΄,
(1) μ‘μ
κ°μ²΄λ type
μμ±κ°μ΄ μ‘΄μ¬ν΄μΌ νλ€. type
μμ±κ°μΌλ‘ μ‘μ
κ°μ²΄λ₯Ό ꡬλΆνλ€.
(2) type
μμ±κ°μ μ μΈνλ©΄ λλ¨Έμ§λ μνκ°μ μμ νκΈ° μν΄ μ¬μ©λλ μ 보λ€
(3) μ‘μ
κ°μ²΄μ ν¨κ» dispatch
λ©μλλ₯Ό νΈμΆνλ©΄ μνκ°μ΄ λ³κ²½λλ€.
리λμ€μ μνκ°μ μμ νλ μ μΌν λ°©λ²μ μ‘μ
κ°μ²΄
μ dispatch
λ©μλλ₯Ό νΈμΆνλ κ²μ΄λ€. λ€λ₯Έ λ°©λ²μΌλ‘ μνκ°μ μμ νλ©΄ μ λλ€.
μνκ°μ dispatch
λ©μλκ° νΈμΆλ μμλλ‘ λ¦¬λμ€ λ΄λΆμμ λ³κ²½λλ€
λΆλ³ κ°μ²΄λ₯Ό μ¬μ©νλ μ΄μ λ, μ΄μ μνκ°κ³Ό μ΄ν μνκ°μ λΉκ΅ν΄μ λ³κ²½ μ¬λΆλ₯Ό νμ ν λ μ 리νκΈ° λλ¬Έμ΄λ€. λΆλ³ κ°μ²΄λ₯Ό μ¬μ©νμ§ μκ³ μ§μ μνκ°μ μμ νκ² λλ©΄ μ΄μ μνκ° λΉκ΅κ° μ΄λ ΅λ€.
3. μνκ°μ μμ ν¨μμ μν΄μλ§ λ³κ²½λμ΄μΌ νλ€
리λμ(reducer): 리λμ€μμ μνκ°μ λ³κ²½νλ ν¨μ (state, action) => nextState
리λμλ μ΄μ μνκ°κ³Ό μ‘μ κ°μ²΄λ₯Ό μ λ ₯λ°μ μλ‘μ΄ μνκ°μ λ§λλ μμ ν¨μμ΄λ€.
μμ ν¨μλ
side effect
(μ μ λ³μμ κ°μ μμ νκ±°λ API μμ²μ 보λ΄λ λ± ν¨μ μΈλΆμ μνλ₯Ό λ³κ²½μν€λ κ²)λ₯Ό λ°μμν€μ§ μμμΌ νκ³ ,- κ°μ μΈμμ λν΄ νμ κ°μ κ°μ λ°νν΄μΌ νλ€.
- λλ€ ν¨μλ μκ° ν¨μλ₯Ό μ΄μ©νλ©΄ μμ ν¨μκ° μλλ€.
- κ°μ μΈμλ₯Ό μ λ ₯ν΄λ νΈμΆνλ μμ μ λ°λΌ λ€λ₯Έ κ°μ λ°ννκΈ° λλ¬Έμ΄λ€.
μ΄λ¬ν νΉμ± λλΆμ μμ ν¨μλ ν μ€νΈ μ½λλ₯Ό μμ±νκΈ° μ½λ€.
리λμ€μ μ£Όμ κ°λ
- μνκ°μ΄ λ³κ²½λλ κ³Όμ
λ·°(μ»΄ν¬λνΈ)
κ° μνκ°μ λ³κ²½νκ³ μΆμ λλ μ‘μ
μ λ°μμν¨λ€.
μ‘μ
μ λ―Έλ€μ¨μ΄
κ° μ²λ¦¬νκ³ (λ―Έλ€μ¨μ΄μ μνλ κΈ°λ₯ μΆκ°λ κ°λ₯νλ€)
리λμ
λ μ‘μ
μ μν΄μ μνκ°μ΄ μ΄λ»κ² λ³κ²½λλμ§ λ‘μ§μ λ΄κ³ μλ€. 리λμλ μλ‘μ μνκ°μ μΆλ ₯νλλ°, κ·Έ μλ‘μ΄ μνκ°μ
μ€ν μ΄
μκ² μλ €μ£Όλ©΄ μ€ν μ΄λ μνκ°μ μ μ₯νλ€. λ³κ²½λ μνκ°μ λ€μ λ·°μκ² μλ €μ€λ€.
π μνκ°μ λ³κ²½νλ κ³Όμ μμ κ±°μΉκ² λλ 4κ°μ§ μμ
- π© μ‘μ
dispatch
λ μ‘μ μ΄ λ°μνλ€λ κ²μ 리λμ€μκ² μλ €μ£Όλ ν¨μ- (2)
action creator
λ₯Ό λ§λ€μ΄μ μ¬μ©νλ μ΄μ λ, κ° μ‘μ κ°μ²΄μ ꡬ쑰λ₯Ό μΌκ΄μ± μκ² μμ±νκΈ° μν¨ - (3) μ‘μ
type
μ μμ λ³μλ‘ κ΄λ¦¬νλ μ΄μ λ,action creator
μμλ μ¬μ©νμ§λ§reducer
μμλ μ¬μ©νκΈ° λλ¬Έ
// (1) dispatch()λ₯Ό νΈμΆν λ μ‘μ
κ°μ²΄λ₯Ό μ§μ μ
λ ₯ν case
store.dispatch({
type: 'todo/ADD' // type: μ‘μ
μ ꡬλΆνλ μμ±κ°μ΄λ―λ‘ κ³ μ ν΄μΌ νλ€.
title: '리λμ€ κ³΅λΆνκΈ°'
});
// (2) action creator ν¨μλ₯Ό λ§λ€μ΄μ νΈμΆν case
const ADD = 'todo/ADD' // (3) μ‘μ
typeμ μμ λ³μλ‘ κ΄λ¦¬
function addTodo(title) {
return { type: ADD, title }
}
store.dispatch(addTodo({ title: '리λμ€ κ³΅λΆνκΈ°' }))
-
π© λ―Έλ€μ¨μ΄
λ―Έλ€μ¨μ΄(middleware)λ 리λμκ° μ‘μ μ μ²λ¦¬νκΈ° μ μ μ€ννλ ν¨μ
- λ―Έλ€μ¨μ΄μ κΈ°λ³Έ ꡬ쑰
- ν¨μ μΈ κ°κ° μ€μ²©λ κ΅¬μ‘°λ‘ λμ΄μλ€.
- λ―Έλ€μ¨μ΄μ κΈ°λ³Έ ꡬ쑰
// λ―Έλ€μ¨μ΄μ κΈ°λ³Έ ꡬ쑰: νμ΄ν μ¬μ©
const myMiddleware = (store) => (next) => (action) => next(action);
// λ―Έλ€μ¨μ΄μ κΈ°λ³Έ ꡬ쑰: νμ΄ν μ¬μ©X
const myMiddleware = function (store) {
return function (next) {
return function (action) {
return next(action);
};
};
};
π± λ―Έλ€μ¨μ΄ μμ± μμ
const middleware1 = (store) => (next) => (action) => {
console.log("middleware1 start"); // (2)
const result = next(action); // (3)
console.log("middleware1 end"); // (8)
return result;
};
const middleware2 = (store) => (next) => (action) => {
console.log("middleware2 start"); // (4)
const result = next(action); // (5)
console.log("middleware2 end"); // (7)
return result;
};
const myReducer = (state, action) => {
console.log("myReducer"); // (6)
return state;
};
const store = createStore(myReducer, applyMiddleware(middleware1, middleware2));
store.dispatch({ type: "someAction" }); // (1)
(1) μ‘μ
μ΄ λ°μνμ λ λ―Έλ€μ¨μ΄λΆν° μ²λ¦¬κ° λλ€.
첫 λ²μ§Έ λ―Έλ€μ¨μ΄ middleware1
κ° μ€νλκ³ (2)κ° μΆλ ₯λλ€. κ·Έ λ€μ μ€μ (3)next
λ₯Ό νΈμΆνμ λ (4)μ΄ μΆλ ₯λλ€.
(3)next
λ middleware2
λ₯Ό μλ―Ένλ€.
(5)next
λ μκΈ° λλ¬Έμ (5)next
λ reducer
λ₯Ό νΈμΆνλ€.
κ·Έλμ (6)λ₯Ό μΆλ ₯νκ² λκ³ (5)next
μΈ myReducer()
κ° μ’
λ£λλ©΄μ (7)μ΄ μΆλ ₯λκ³ (8)μ΄ μΆλ ₯λλ€.
μ¦, λ―Έλ€μ¨μ΄μ μμλλ‘ νΈμΆλκ³ nextλ₯Ό νΈμΆνλ©΄μ λ€μ λ―Έλ€μ¨μ΄λ₯Ό νΈμΆνκ² λκ³ λ§μ§λ§ λ―Έλ€μ¨μ΄μμλ 리λμλ₯Ό νΈμΆνλ€.
μνκ° λ³κ²½μ κ²μ¬νλ μ½λλ κ° μ΄λ²€νΈ μ²λ¦¬ ν¨μμμ ꡬνν΄μΌ νλλ°, react-redux
ν¨ν€μ§μ connect
ν¨μμμλ μ체μ μΌλ‘ μνκ° λ³κ²½μ κ²μ¬νλ€.
-
π© 리λμ
리λμ(reducer)λ μ‘μ μ λ°μνμ λ μλ‘μ΄ μνκ°μ λ§λλ ν¨μλ€
- 리λμμ κΈ°λ³Έ ꡬ쑰
(state, action) => nextState;
π± 리λμ μμ± μμ
function reducer(state = INITIAL_STATE, action) { // (1) state = INITIAL_STATE
switch (action.type){ // (2) μ‘μ
νμ
λ³ caseλ‘ μ²λ¦¬
case REMOVE_ALL :
return { ...state, todos: [] } // (3) λΆλ³ κ°μ²΄λ‘ κ΄λ¦¬
case REMOVE :
return { ...state, todos state.todos.filter(todo => todo.id !== action.id) }
default :
return state; // (4)
}
}
const INITIAL_STATE = { todos: [] }
리λμ€λ μ€ν μ΄λ₯Ό νΈμΆν λ μνκ°μ΄ μλ μνλ‘ λ¦¬λμλ₯Ό νΈμΆνλ―λ‘
(1) 맀κ°λ³μμ κΈ°λ³Έκ°μ μ¬μ©ν΄μ μ΄κΈ° μνκ°μ μ μνλ€.
(2) κ° μ‘μ
νμ
λ³λ‘ switch case
λ¬Έμ λ§λ€μ΄μ μ²λ¦¬νλ€.
(3) μνκ°μ λΆλ³ κ°μ²΄λ‘ κ΄λ¦¬ν΄μΌ νλ―λ‘ μμ ν λ λ§λ€ μλ‘μ΄ κ°μ²΄λ₯Ό μμ±νλ€.
(4) μ²λ¦¬ν μ‘μ
μ΄ μλ€λ©΄ μνκ°μ λ³κ²½νμ§ μλλ€.
λΆλ³ κ°μ²΄λ₯Ό κ΄λ¦¬ν λͺ©μ μΌλ‘ μ΄λ¨Έ(immer) ν¨ν€μ§λ₯Ό μ¬μ©νλ€
π± μ΄λ¨Έ(immer)λ₯Ό μ¬μ©ν΄μ λΆλ³ κ°μ²΄λ₯Ό κ΄λ¦¬νλ μμ
import produce from "immer";
const person = { name: "yurim", age: 20 };
const newPerson = produce(person, (draft) => {
// (1)
draft.age = 30;
});
(1) produce()
μ 첫 λ²μ§Έ μΈμλ λ³κ²½νκ³ μ νλ κ°μ²΄,
λ λ²μ§Έ μΈμλ 첫 λ²μ§Έ μΈμλ‘ λ°μ κ°μ²΄λ₯Ό μμ νλ ν¨μ
draft
κ°μ²΄λ₯Ό μμ νλ©΄ produce()
κ° μλ‘μ΄ κ°μ²΄λ₯Ό λ°ννλ€.
π± μ΄λ¨Έ(immer)λ₯Ό μ¬μ©ν΄μ μμ μ½λ 리νν λ§ νκΈ°
function reducer(state = INITIAL_STATE, action) {
return produce(state, draft => {
switch (action.type){
case ADD :
return { draft.todos.push(action.todo) } // (1)
case REMOVE_ALL :
return { draft.todos = [] }
case REMOVE :
return { draft.todos = draft.todos.filter(todo => todo.id !== action.id) }
default :
return state;
}
})
}
const INITIAL_STATE = { todos: [] }
(1) draft
κ° μλ‘μ΄ κ°μ²΄λ₯Ό λ°ννλ―λ‘, push
λ©μλλ₯Ό μ¬μ©ν΄λ κΈ°μ‘΄ μνκ°μ μ§μ μμ λμ§ μλλ€.
π± createReducer()
λ‘ λ¦¬λμ μμ±νκΈ°
switch
λ¬Έ λ³΄λ€ λ κ°κ²°νκ² λ¦¬λμ ν¨μλ₯Ό μμ±ν μ μλ€
function reducer(state = INITIAL_STATE, { // (1)
[ADD]: (state, action) => state.todos.push(action.todo),
[REMOVE_ALL]: state => ( state.todos = [] ),
[REMOVE]: (state, action) => (state.todos = state.todos.filter(todo => todo.id !== action.id))
})
첫 λ²μ§Έ μΈμλ‘ μ΄κΈ°κ°μ λ°κ³ , (1) λ λ²μ§Έ μΈμλ‘ μ‘μ μ²λ¦¬ ν¨μλ₯Ό λ΄κ³ μλ κ°μ²΄λ₯Ό λ°λλ€.
-
π© μ€ν μ΄
μ€ν μ΄(store)λ 리λμ€μ μνκ°μ κ°μ§λ κ°μ²΄. μ‘μ μ λ°μμ μ€ν μ΄μ dispatch()λ‘ μμλλ€
- 리λμ€μ 첫 λ²μ§Έ μμΉμ λ°λΌ μ 체 μνκ°μ νλμ
store
κ°μ²΄μ μ μ₯νλ€. - νμ§λ§ μ¬λ¬κ°μ
store
κ°μ²΄λ₯Ό μ¬μ©ν΄λ λ¬Έμ κ° λμ§ μλλ€. - λ¨μν λ°μ΄ν° μ’
λ₯μ λ°λΌ ꡬλΆνκΈ° μν μ©λλΌλ©΄
combineReducer()
λ₯Ό μ¬μ©νλ©΄ λλ€. - νΉλ³ν μ΄μ κ° μλ€λ©΄ μ€ν μ΄λ νλλ§ λ§λλ κ² μ’λ€.
β¨ tl;dr
리λμ€λ
- μ 체 μνκ°μ νλμ
store
κ°μ²΄μ μ μ₯νλ€. - μ‘μ
κ°μ²΄λ‘ μνκ° λ³κ²½μ΄ κ°λ₯νλ°,
- μ‘μ
κ°μ²΄λ
type
μμ±κ°μΌλ‘ μ‘μ κ°μ²΄λ₯Ό ꡬλΆνλ€. - μ‘μ
κ°μ²΄μ ν¨κ»
dispatch
λ©μλλ‘ μνκ°μ λ³κ²½νλ€
- μ‘μ
κ°μ²΄λ
- λ―Έλ€μ¨μ΄λ 리λμκ° μ‘μ
μ μ²λ¦¬νκΈ° μ μ μ€ννλ ν¨μλ€.
- λ°μ΄ν°λ₯Ό μ²λ¦¬νλ μ€κ° κ³Όμ μμ λ‘μ§μ λ£μ΄μ νμν κΈ°λ₯μ μΆκ°ν μ μλ€ (ex. redux-saga)
- λλ²κΉ λͺ©μ μΌλ‘ μνκ° λ³κ²½ μ λ‘κ·Έλ₯Ό μΆλ ₯νκ±°λ
- 리λμμμ λ°μν μμΈλ₯Ό μλ²λ‘ μ μ‘νλ λ±μ λͺ©μ μΌλ‘ λ―Έλ€μ¨μ΄κ° νμ©λλ€.
- λ°μ΄ν°λ₯Ό μ²λ¦¬νλ μ€κ° κ³Όμ μμ λ‘μ§μ λ£μ΄μ νμν κΈ°λ₯μ μΆκ°ν μ μλ€ (ex. redux-saga)
- 리λμλ μ‘μ
μ΄ λ°μνμ λ μλ‘μ΄ μνκ°μ λ§λλ ν¨μ.
- 리λμ€μ μνκ°μ μμ νλ μ μΌν λ°©λ²μ
- μ‘μ
κ°μ²΄μ
dispatch
λ©μλλ₯Ό νΈμΆνλ κ²μ΄λ€.
- μ‘μ
κ°μ²΄μ
- λΆλ³ κ°μ²΄λ₯Ό κ΄λ¦¬ν λͺ©μ μΌλ‘
μ΄λ¨Έ(immer)
ν¨ν€μ§λ₯Ό μ¬μ©νλ€ - 리λμ μμ± μ μ£Όμν μ
- λ°μ΄ν° μ°Έμ‘°: 리λμ€μ μνκ°μ λΆλ³ κ°μ²΄μ΄κΈ° λλ¬Έμ μΈμ λ μ§ κ°μ²΄μ μ°Έμ‘°κ°μ΄ λ³κ²½λ μ μμΌλ―λ‘ κ°μ²΄λ₯Ό μ°Έμ‘°ν λλ κ³ μ ν IDκ°μ μ΄μ©νλκ² μ’λ€
- μμ ν¨μ: λλ€ν¨μ, μκ°ν¨μ λ± νΈμΆνλ μμ μ λ°λΌ λ€λ₯Έ κ°μ΄ λ°νλ μ μμΌλ―λ‘ μ¬μ©νλ©΄ μ λλ€.
- 리λμ€μ μνκ°μ μμ νλ μ μΌν λ°©λ²μ
- μ€ν μ΄λ 리λμ€μ μνκ°μ κ°μ§λ κ°μ²΄. μ‘μ μ λ°μμ μ€ν μ΄μ dispatch()λ‘ μμλλ€
- 리λμ€λ λ¨λ°©ν₯ λ°μ΄ν° νλ¦μ νΉμ±μ μ§λκΈ° λλ¬Έμ μλΉν μ§κ΄μ μ΄κ³ μμΈ‘ κ°λ₯νλ€λ μ₯μ μ΄ μλ€. (κ°λ¨νκ³ μ§κ΄μ μΈ κ΅¬μ‘°)