티스토리 뷰
설치
1. 프로젝트 생성 시
# Redux + Plain JS template
npx create-react-app my-app --template redux
# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript
2. 기존 프로젝트에 설치
redux toolkit을 설치하면 redux도 설치되기 때문에 redux를 따로 설치해 줄 필요 없음
npm install @reduxjs/toolkit
createSlice
기존 action + reducer
createSlice를 사용하여 기존 action, reducer의 단점을 피할 수 있음
- type의 이름을 정하기 번거로움
- type 작성 시 오타날 수 있음
- 타입별로 if/else, switch/case 작성해줘야 해서 번거로움
createSlice는 세 개의 키를 갖는 객체를 매개변수로 받음
1. name
해당 상태의 이름. 이 이름으로 action type을 알아서 만들어줌
2. initialState
reducer에서 사용할 상태 초기값
3. reducers
값으로 객체를 가짐.
기존 case를 함수로 만들기, state와 action을 매개변수로 받음
기존에 상태(state)를 변경를 변경하면 안돼서 복사(Object.assign, arr.slice, spread)를 사용했던 것과 달리
redux toolkit은 상태를 알아서 처리해주기 때문에
- 상태를 바로 변경하고
- return을 생략할 수 있음
import { createSlice } from "@reduxjs/toolkit";
import { initialState } from "./initialState";
const itemSlice = createSlice({
name: 'item',
initialState,
reducers: {
addToCart: (state, action) => {
state.cartItems.push(action.payload)
},
removeFromCart: (state,action) => {
const removed = state.cartItems.filter((item) => item.itemId !== action.payload.itemId)
state.cartItems = removed
},
setQuantity: (state, action) => {
let idx = state.cartItems.findIndex(el => el.itemId === action.payload.itemId)
state.cartItems[idx] = action.payload
}
}
})
// Action Creator로 사용하기 위해 export
export const itemActions = itemSlice.actions
// store에 저장하기 위해 export
export default itemSlice.reducer
reducers 함수의 인자가 action.payload로 저장되어 전달됨
import { itemActions } from '../reducers/itemReducer'
function ItemListContainer() {
// 생략
const handleClick = (item) => {
if (!cartItems.map((el) => el.itemId).includes(item.id)) {
dispatch(itemActions.addToCart({itemId: item.id}))
}
}
return (
// 생략
}
configureStore
기존 createStore
createStore 사용 시 프로젝트를 위해 아래 코드 작성이 필요했었는데
- combineReducers 여러 리듀서를 하나로 묶기 위해 필요
- thunk 비동기 작업을 위한 미들웨어
- applyMiddleware 미들웨어를 적용하기 위해 필요
- composeWithDevTools
configureStore를 사용하면 자동으로 설정되어있어 작성해줄 필요 없음
매개변수로 reducer 키를 갖는 객체를 받으며,
reducer가 여럿인 경우 값을 객체로 받아주면 됨(combineReducers 사용할 필요 없음)
// reducer가 하나인 경우
const store = configureStore({ reducer: itemReducer })
// reducer가 여럿인 경우
const store = configureStore({
reducer: {
itemReducer,
notificationReducer
}
})
import { configureStore } from "@reduxjs/toolkit";
import itemReducer from '../reducers/itemReducer';
import notificationReducer from '../reducers/notificationReducer';
const store = configureStore({
reducer: {
itemReducer,
notificationReducer
}
})
export default store;
createAsyncThunk
비동기 작업만을 위한 함수를 만들어줌
해당 함수에서는 비동기 작업만하고, 상태 변경은 createSlice의 extraReducers에서 진행해야함
기본 형태
const fetchUserById = createAsyncThunk(
'users/fetchByIdStatus',
async (userId: number, thunkAPI) => {
const response = await userAPI.fetchById(userId)
return response.data
}
)
const usersSlice = createSlice({
name: 'users',
initialState,
reducers: {
// 일반 상태 변경 함수
},
// 비동기 작업
extraReducers: (builder) => {
builder.addCase(fetchUserById.fulfilled, (state, action) => {
state.entities.push(action.payload)
})
},
})
Action Creator의 이름을 정해줌(fetchUserById)
createAsyncThunk는 매개변수로 type의 이름과 비동기로 작업할 함수를 받음('users/fetchByIdStatus', async함수)
여기서 async 함수의 return값은 createSlice extraReducers의 action.payload로 접근
(builder의 addCase 메서드 첫 번째 인자가 async 함수, 두 번째 인자가 action)
createSlice 내부에서 비동기함수가 pending, fulfilled, rejected(대기, 완료, 거부)인 경우 진행할 작업을 함수로 작성해줌
(전부 작성하지 않고 fulfilled만 작성해도 됨)
pending상태에서 action.payload에 접근하려면
action.meta.arg
참고
Youtube- 아직도 옛날 리덕스 쓴다고..? 옛날 리덕스를 최신 리덕스 Toolkit으로 바꿔보자!
Youtube- redux toolkit - thunk 를 이용해서 비동기 작업을 처리하는 방법
2023.01.01
'코드스테이츠(SEB_FE_42)' 카테고리의 다른 글
[네트워크] 네트워크 계층 모델, HTTPS (0) | 2023.01.03 |
---|---|
[사용자 친화 웹] 웹 접근성 (0) | 2023.01.02 |
[사용자 친화 웹] 웹 표준 (0) | 2022.12.30 |
[React] Redux-thunk, Redux Toolkit (0) | 2022.12.29 |
[React] Redux (0) | 2022.12.28 |