기존의 리덕스가 아닌 리덕스 툴킷을 사용하는 이유는 무엇일까?
- 기존의 리덕스는 환경설정시 작성해야 하는 코드와 사용할 파일이 너무 많아 복잡하다.
- 리덕스 툴킷은 필요한 모듈을 담고 있는 도구모음과 같다.
- 리덕스 툴킷이 담고 있는 createAsyncThunk로 비동기 처리를 비교적 쉽게 할 수 있다.
- 리덕스 툴킷은 immer 패키지를 갖고 있으므로 불변성을 지켜가며 작성할 필요가 없다.
설치 방법은 다음과 같다.
이미 앱이 존재할 때.
npm i @reduxjs/toolkit
CRA로 앱을 설치할 때.
npx create-react-app my-app --template redux
npx create-react-app my-app --template redux-typescript
장바구니 예제를 통해 리덕스 툴킷 사용법을 익혀본다.
slice는 createSlice로 생성하며 createSlice의 인자로 들어가는 객체는
1. name (이름)
2. initailState (초기값)
3. reducers (리듀서 함수) -> action creator 생성.
로 구성된다.
사용법
src/redux/modules/cartSlice.js
import { createSlice } from '@reduxjs/toolkit'
const cartSlice = createSlice({
name: "cart",
initialState: [],
reducers: {
addReducer: (state, action) => {
state = state.push(action.payload)
},
},
})
// dispatch로 쉽게 접근하기 위해 구조분해 할당.
export const { addReducer } = cartSlice.actions
export default cartSlice
store는 configureStore로 생성하며 여러 slice들을 한데 모아주는 역할을 한다.
reducer을 reducers로 착각하지 않도록 주의해야 한다.
사용법
src/redux/configureStore.js
import { configureStore } from '@reduxjs/toolkit'
import cartSlice from '../redux/modules/cartSlice'
const rootReducer = combineReducers({
cart: cartSlice.reducer,
})
const store = configureStore({
reducer: rootReducer,
})
export default store
리액트 프로젝트와 생성한 store를 연결하여야 한다.
이를 위해 index.js에서 store를 불러와 provider로 하위컴포넌트로 뿌려준다.
사용법
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from "react-redux";
import store from "./redux/configStore";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
useSelector를 이용해 store의 데이터를 조회할 수 있다.
사용법
import { useSelector } from 'react-redux'
const cart = useSelector(state => state.cart)
리듀서에서 생성한 action creator를 발생시킬 수 있다.
action creator의 인자로 값을 넣으면 이를 reducer에서 action payload로 사용할 수 있다.
사용법
import { useDispatch } from 'react-redux'
const dispatch = useDispacth()
dispatch(addReducer(product))
리덕스 툴킷에서 따로 미들웨어를 설정할 필요 없이 비동기 처리를 해주는 기능인 createAsyncThunk를 사용할 수 있다.
상품 목록 예제를 통해 익혀본다.
- createAsyncThunk
- 첫번째 인자로 action의 이름을, 두번째 인자로 비동기 처리를 할 함수를 입력한다.
- createSlice
- extraReducers에서 pending, fullfilled, rejected 세 가지 경우의 처리 결과를 넣어준다.
src/redux/modules/productsSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
//asyncThunk 생성
export const loadProducts = createAsyncThunk(
//action 이름
"load/products"
//비동기 처리
async () => {
const res = await axios.get('http://localhost:5008/products')
const products = res.json()
//action의 payload로 리턴
//products === action.payload
return products
}
)
//slice 생성
const productsSlice = createSlice({
name: products,
intialState: {
list: [],
status: null,
},
extraReducers: {
[loadProducts.pending]: (state, action) => {
state.status = 'pending'
},
[loadProducts.fullfilled]: (state, action) => {
state.list = [...action.payload]
state.status = 'fullfilled'
},
[loadProducts.rejected]: (state, action) => {
state.status = 'rejected'
},
},
})
export default productsSlice.reducer
store는 configureStore로 생성하며 여러 slice들을 한데 모아주는 역할을 한다.
reducer을 reducers로 착각하지 않도록 주의해야 한다.
사용법
src/redux/configureStore.js
import { configureStore } from '@reduxjs/toolkit'
import cartSlice from '../modules/cartSlice'
import productSlice from '../modules/productsSlice'
const store = configureStore({
reducer: {
cart: cartSlice,
products: productsSlice,
},
})
export default store
createAsyncThunk 함수를 dispatch해준다.
//createAsyncThunk로 생성한 비동기 처리 함수
import { loadProducts } from "./redux/modules/productsSlice";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
const App = () => {
const productList = useSelector(state => state.products.list)
const dispatch = useDispatch()
useEffect(() => {
dispatch(loadProducts())
}, [])
}