지난 시간에는 React Redux 상태관리 라이브러리를 간단하게 사용해보았고 이번에는 좀더 파고들어서 어떤 기능이 있는지 알아보자
본 글은 Redux 예제 - 장바구니 만들기를 참고해서 만들었습니다.
폴더 구조
src
|
| -store
|
| -actions
| |
| | - index.js
|
|-reducers
|
| - index.js
| - cartReducer.js
기본 설치
먼저 라우터를 구현해야합니다
yarn add react-router-dom && npm install react-router-dom
기본 router-dom을 깔아주시고 Redux 도 필요하기 때문에
yarn add redux react-redux && npm i redux react-redux
둘중 하나 써서 깔아주세요
actions
actions 폴더의 index.js에서 액션을 생성하는 액션 생성 함수를 정의 해줍니다.
- 액션은 type이라는 속성 값을 가진 js객체이다.
- 액션 생성함수는 그 액션 객체에 생성하는 역할을 하는 js 함수이다.
- 액션 객체를 dispatch 메서드에 넣어서 호출한다.(useDispatch)
- 액션 생성함수가 생성한 액션 객체는 reducer를 거쳐 store를 업데이트 하게 된다.
// store -> actions -> index.js
export const addCart = (item) => {
return {
type: "ADD_ITEM",
payload: item
}
}
// type 이라는 속성을 가진 액션을 생성하는 addCart는 액션 생성함수이다.// 이름만 봐도 장바구니 담는 역할을 한다.
export const deleteCart = (items) => {
return {
type:"DELETE_ITEM",
payload:items
}
}
reducers
reducers 폴더의 cartReducer.js 파일에서 장바구니와 관련된 reducer 함수를 작성한다.
프로젝트가 크다면 서로 다른 주제별로 reducer를 만들 수 있다. 이렇게 다른 주제의 reducer들은
결국 rootReducer 로 모이게 된다.
// store -> reducers -> cartReducer.js
const cartReducer = (state = [], action) => {
switch(action.type) {
case "ADD_ITEM":
return [...state, action.payload];
case "DELETE_ITEM":
return [...action.payload];
default:
return state;
}
}
export default cartReducer;
// store -> reducers -> index.js
// 이곳이 root reducer
import { combineReducers } from "redux";
import cartReducer from "./cartReducer";
export default combineReducers({ cartReducer });
// redux 에서 제공하는 combineReducers 를 통해 주제별로 나눈 조각 reducer (여기서는 cartReducer만 존재) 들을 rootReducer 로 모아준다.
이렇게 모아진 rootReducer는 전체 파일을 렌더하고 있는 index.js 에서 사용할 수 있다.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Routes from './Routes';
import reportWebVitals from './reportWebVitals';
import { Provider } from "react-redux";
import { createStore } from "redux";
import rootReducer from './store/reducers/';
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<Routes />
</Provider>
,document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
// redux 에서 제공하는 createStore를 통해 우리가 만든 rootReducer를 import로 받아와 store라는
// 이름으로 저장함.
// react-redux 에서 제공하는 Provider 를 통해 프로젝트 전역에서 바라볼 수 있도록 해준다.
기능 구현
useDispatch
ProductItem.js 컴포넌트에서 useDispatch 와 actions 에서 작성해 둔 액션 생성함수를 import로 받아와 사용한다.
현재 ProductItem 컴포넌트는 부모 컴포넌트에서 map을 돌리고 있다. props로 내려오는 선택한 item 에 관한 데이터를
"장바구니 담기" 버튼을 클릭시 addCart의 인자로 넘겨주면 된다.
아래와 같이 action으로 값을 올려줄 때 useDispatch 라는 훅을 사용한다.
이렇게 하면 장바구니에 담기로 선택한 아이템에 관한 데이터가 actions 의 addCart를 거쳐서 reducer에서 switch문을 만나게 된다. switch 문에서는 action의 type 이 "ADD_CART" 라면 기존의 state에 전달받은 데이터 payload를 추가시킨다.
이렇게 store가 업데이트 되면서 해당 store를 구독하고 있는 컴포넌트의 값이 저절로 바뀌게 된다.
useSelector
현재 상품 리스트 페이지에서 각 상품들을 장바구니에 담으면 store 에 하나씩 업데이트 된다.
이렇게 업데이트 된 store를 구독하는 법을 알아보자. store를 구독하려면 useSelector라는 훅이 필요하다.
useSelector 를 사용하여 store 에 접근하여 store의 조각인 cartReducer 즉, 장바구니에 담기 버튼을 클릭할 때마다
업데이트 되는 장바구니에 담긴 상품들의 배열을 cart라는 변수에 담아서 아래에서 map을 돌려주면서 장바구니를 나열하는
기능을 구현한다.
현재 actions 의 addCart라는 액션 생성함수를 이용해 장바구니에 상품을 추가하는 기능을 구현했습니다. 이와 같은 원리로 Nav컴포넌트도 store를 구독하게 한다면 store가 업데이트 될때마다 장바구니 갯수가 자동으로 업데이트 된다.
장바구니의 상품을 삭제하는 기능 역시 같은 원리로 filter를 사용한다면 업렵지 않게 구현할 수 있다.
참고 자료
'프론트 엔드 > React' 카테고리의 다른 글
Typescript && Webpack && Babel이란 무엇일까 - 웹개발 필수 라이브러리 (0) | 2021.08.28 |
---|---|
[Jest] Mock Function (0) | 2021.08.28 |
[Jest] Jest를 사용한 비동기 코드 검사 (0) | 2021.08.28 |