과제로 Cmarket 웹 앱을 Redux로 상태를 관리하도록 만들어보았다.
상태 변경 로직을 컴포넌트로부터 분리하는, Redux의 설계를 알아가보는 과제였다.
Action ➞ Dispatch ➞ Reducer ➞ Store
create-react-app으로 만든 react 웹 애플리케이션에 redux 라이브러리를 적용한 구조
점점 과제 파일이 복잡해져서 파악하는 것부터 과제의 시작이다.
알아보기 쉽도록 위와 같이 컴포넌트 관계 도면을 만들어보았다.
Action/index.js
Action creater functions를 module화 하여 구현했기 때문에
ItemListContainer
와ShoppingCart
컴포넌트에서 원하는 action을 import해서 사용할 수 있다.
export const ADD_TO_CART = "ADD_TO_CART";
export const addToCart = (itemId) => {
return {
type: ADD_TO_CART,
payload: {
quantity: 1,
itemId
}
}
}
ItemListContainer
, ShoppingCart
컴포넌트
useSelector() Hook을 통해 store의 저장되어 있는 state와 연결된다.
//useSelector(): 컴포넌트와 state를 연결하는 역할을 한다.
const state = useSelector(state => state.itemReducer);
const { items, cartItems } = state;
//이제 컴포넌트 내부에서 items, cartItems로 state에 접근 가능
useDispatch() Hook을 사용하여
클릭 등의 이벤트가 발생하면 이벤트 핸들러 안에서 dispatch 함수를 호출한다.
//dispatch(액션생성자(인자));
dispatch(notify(`장바구니에 ${item.name}이(가) 추가되었습니다.`));
dispatch(setQuantity(itemId, quantity));
action을 dispatch하면 reducer가 호출된다.
dispatch 함수는 action 객체를 직접, 또는 action 생성자를 인자로 전달받아 Reducer 함수를 호출한다.
컴포넌트 외부에 있는 Reducer함수는 dispatch 함수로부터 action 객체를 전달받는다.
전달받은 action 객체의type
에 따라 분기하여 상태를 변경시킨다.
Reducer 함수는 외부 요인으로 인해 state가 변경되지 않도록 순수 함수로 작성해야 한다.
const itemReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_TO_CART:
return Object.assign({}, state, {
cartItems: [...state.cartItems, action.payload]
})
default:
return state;
}
Redux의 state 업데이트는 immutable한 방식이어야 한다.
state 자체를 건드리면 안되고,
Object.assign()
등의 방식을 사용해서 기존 state와 다른, 새로운 state를 return해야 한다.
모든 컴포넌트를 불러와서 html에 render되는 index 파일은 아래와 같이 구현되어 있다.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import store from './store/store';
import { Provider } from 'react-redux';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
Provider
컴포넌트는 react-redux 라이브러리에 내장되어 있는 컴포넌트다.
props로store={myStore}
값을 설정해줌으로 react 앱에 store을 연동할 수 있게 한다.