Redux, 이것만은 알고 갑시다!
1. 리듀서는 여러개일 수 있습니다.
실무에서는 여러개의 리듀서를 합치는 작업을 통해 단일 리듀서가 비대해지는 것을 방지합니다. 대부분의 리듀서는 파일 분기를 통해 관리합니다.
const rootReducer = combineReducers({
aReducer,
bReducer,
cReducer,
dReducer,
eReducer,
});
2. 단일 스토어로 관리합니다.
상태를 저장하는 스토어는 하나만 사용합니다. 상태가 한 개 이상이라면 관리해야 하는 모든 상태는 하나의 스토어 안에서 객체 구조로 혹은 배열 형태로 저장해서 사용하면 됩니다.
console.log(store.getState())
{
quantity : 3,
disabled : true,
todos : [{
text : 'have a lunch',
completed : true,
},{
text : "study Redux",
completed : false
}]
}
import { createStore } from 'redux';
const reducer = (state, action) => {
switch (action.type) {
case 'ADD_USER':
return [...state, action.payload];
default:
return [
{ id: 1, name: '한재현' },
{ id: 2, name: '이호준' },
];
}
};
const store = createStore(reducer);
// 스토어에 배열을 추가합니다.
store.dispatch({ type: 'ADD_USER', payload: { id: 4, name: '개리원' } });
// 스토어에서 객체를 가져옵니다.
const user = store.getState().find((user) => user.id === 4);
3. state는 읽기 전용입니다.
리덕스는 값을 읽기만 하며, 리듀서를 통해 state를 업데이트 할때는 기존의 객체나 배열은 건드리지 않고 새로운 값으로 생성해주어야 합니다. 즉, 기존 state를 수정하지 않고 새로운 state 객체를 통해 업데이트를 해야 이전 상태에 대한 데이터 추적이 가능합니다.
const a = [1,2,3]
const b = a
console.log(a === b) // true
-------------------------------------------------------------
const a = [1,2,3]
const b = [...a]
console.log(a === b) // false
-------------------------------------------------------------
const reducer = (state = [], action) => {
switch (action.type) {
case "ADD":
return [...state,{ text: action.text }];
default:
return state;
}
};
4. 데이터에 따라 선택적 갱신이 가능합니다.
앞에서 말한 것처럼 Context는 가지고 있는 state가 하나만 변경되어도 Context의 값을 가지고 있는 모든 컴포넌트가 리렌더링이 되버립니다. 리덕스는 선택적 갱신이 가능합니다.
랜더 함수가 구독하고 있는 state의 값이 변경되었을 때만 컴포넌트를 리렌더링합니다.
5. 순수 함수로 작성되어야 합니다.
state의 값을 업데이트 하는 유일한 방법인 reducer 함수는 반드시 순수 함수로 만들어야 합니다.
순수 함수란 동일한 아규먼트라면 언제나 동일한 return 값을 반환하는 함수를 의미합니다. 아래와 같은 함수는 함수 외부 변수의 영향을 받기 때문에 순수 함수라고 할 수 없습니다.
let x = 10; // x가 변하면 아래 함수에 영향을 끼침
function plus(y) {
y = y + x;
return y;
}
plus(100);
리듀서 함수는 이전 상태(state)와 액션 객체 파라미터에 대해서만 의존해야 합니다. 파라미터 외의 값들(외부 변수 등)에 영향받으면 안 됩니다.
const reducer = (state = 0, action) => {
switch (action.type) {
case 'ADD':
return state + 1;
default:
return state;
}
};