-
[TIL] 2022.2.27.카테고리 없음 2023. 2. 27. 19:23
리덕스 상태관리
Action
액션은 어떤 액션을 취할 것인지 정의해놓은 액체이다.
export const addToCart = (itemId) => { return { type: ADD_TO_CART, payload: { quantity: 1, itemId, }, }; }; export const removeFromCart = (itemId) => { return { type: REMOVE_FROM_CART, payload: { itemId, }, //TODO }; }; export const setQuantity = (itemId, quantity) => { return { type: SET_QUANTITY, payload: { itemId, quantity, }, //TODO }; };
(위 코드는 장바구니를 구현하기 위해 필요한 액션들을 구현한 코드이다.)
여기서 type은 필수로 지정해주어야 하며 그 외의 것들은 선택적으로 사용할 수 있다. 필요에 따라 payload를 작성해 구체적인 값을 전달한다. 위 코드를 보면 필요한 값을 payloa로 전달해주었다.
Dispatch
Dispatch는 Reducer로 Action을 전달해주는 함수이다. Dispatch의 전달인자로 Action 객체가 전달된다.
function ItemListContainer() { const state = useSelector((state) => state.itemReducer); const { items, cartItems } = state; const dispatch = useDispatch(); const handleClick = (item) => { if (!cartItems.map((el) => el.itemId).includes(item.id)) { dispatch(addToCart(item.id)); //TODO: dispatch 함수를 호출하여 아이템 추가에 대한 액션을 전달하세요. dispatch(notify(`장바구니에 ${item.name}이(가) 추가되었습니다.`)); } else { dispatch(notify("이미 추가된 상품입니다.")); } };
dispatch = useDispatch()로 할당 및 선언해주고,
액션객체를 전달받은 Dispatch함수는 reducer를 호출한다.
위에 보면 useSelector가 있는데, useSelector()는 컴포넌트와 stat을 연결하여 리덕스의 state에 연결할 수 있게 해준다.
state=>state.itemReducer형식으로 상태값을 반환할 수 있다.
Reducer
Reducer는 dispatch에게서 전달받은 액션 객체의 type 값에 따라 상태를 변경시키는 함수이다.
리듀서는 두가지 파라미터를 받아온다. state와 action.
현재 상태와 전달받은 액션을 참고하여 새로운 상태를 만들어 반환한다.
리듀서를 생성할때는 초기상태를 인자로 요구한다. state=initialState
리듀서가 처음 호출될때, state값은 undefined가 된다. 따라서 state의 초깃값을 지정해서 액션이 발생하기전에 이 케이스에 대해 처리해줘야한다. 초깃값을 설정해주지 않을시 오류가 발생하게 된다.
const itemReducer = (state = initialState, action) => { switch (action.type) { case ADD_TO_CART: return Object.assign({}, state, { cartItems: [...state.cartItems, action.payload], }); //TODO break; case REMOVE_FROM_CART: //TODO let currentItem = state.cartItems.filter( (el) => el.itemId !== action.payload.itemId ); return Object.assign({}, state, { cartItems: currentItem }); break; case SET_QUANTITY: let idx = state.cartItems.findIndex( (el) => el.itemId === action.payload.itemId ); //암튼... 저 인덱스에 있는 저것의 quantitiy를 바꿔야함. return Object.assign({}, state, { cartItems: [ ...state.cartItems.slice(0, idx), action.payload, ...state.cartItems.slice(idx + 1), ], }); //TODO break; default: return state; } };
이때 reducer는 순수함수여야한다!
Reducer함수는 immtable한 방식으로 변경해야한다. 즉, 원본을 변경하면 안된다는것이다. 그래서 Object,assign을 통해 새로운 객체를 만들어 리턴하였다.
default: return state를 통해 해당되는 경우가 없을땐 기존상태를 그대로 리턴한다.
Store
state가 관리되는 오직 하나뿐인 저장소의 역할을 한다.
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose; const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk))); export default store;
createStore메서드를 활용해 Reducer를 연결한다.
리덕스 상태관리 순서
1. 상태가 변경되어야 하는 이벤트가 발생하면, 변경될 상태에 대한 정보가 담긴 Action객체가 생성된다.
2. 이 Action객체는 Dispatch함수의 인자로 전달된다.
3. Dispatch함수는 Action 객체를 Reducer함수로 전달한다.
4. Reducer함수는 Action 객체의 값을 확인하고 그 값에 따라 전역상태 저장소 Store의 상태를 변경한다.
5. 상태가 변경되면 리액트는 화면을 다시 렌더링한다.