1. 개요
React에서 상태관리 툴로 Redux를 사용하는데, Redux를 사용하기가 상당히 까다롭고 진입장벽이 높습니다.
액션 함수, 액션 생성 함수, 리듀서, 스토어... 또 타입스크립트를 쓰게 되면 해당 타입을 또 일일히 지정해주어야 하고 관리할 상태값이 1개가 생길 때마다 작성하는 코드도 많아집니다. 가독성도 안좋아지고요...
이러한 문제 때문에 상태관리를 도와주는 라이브러리가 등장하게 되었는데, 사실 Redux Toolkit보다 더 직관적이고 좋은 라이브러리는 많습니다.
다만 상태관리라는 개념에 대해 정확하게 알고 사용하는 것이 좋을 것이라고 생각이 되어 Redux를 먼저 사용해보고 그 Redux를 편리하게 만든 Redux Toolkit에 알아보려고 합니다!
2. 설치
공식사이트는 아래와 같습니다.
https://redux-toolkit.js.org/introduction/getting-started
npm install @reduxjs/toolkit react-redux
공식 사이트에 나온 것처럼 프로젝트에 위 패키지를 설치해 줍니다!
3. 주요 함수 및 실제 사용 코드
리덕스 툴킷을 사용할 때 2개의 함수만 잘 사용하시면 됩니다.
실제 리듀서가 동작하는 createSlice(), store의 구성설정인 configureStore().
아이러니하게도 기능 압축이 잘 된 라이브러리인데, 공식 사이트의 설명이 조금 난해하게 되어 있습니다.
요점만 잘 이해하기 위해서 함수별로 정리해보겠습니다.
3-1.createSlice()
/store/counterSlice.ts
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
interface CounterState {
value: number
}
const initialState = { value: 0 } as CounterState
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment(state) {
state.value++
},
decrement(state) {
state.value--
},
incrementByAmount(state, action: PayloadAction<number>) {
state.value += action.payload
},
},
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
코드는 타입스크립트로 작성되었습니다. 자바스크립트로 된 버전은 공식사이트를 참고해주세요.
위 코드는 카운트를 증감하는 예제입니다.
createSlice함수는 파라미터에 name, initialState, reducers 이 3개를 작성해주면 됩니다.
1) initialState: default값이면서 동시에 상태 관리에 사용되는 type입니다.
interface로 type을 지정하고, initalState의 값을 초기화를 시켜주는데, 카운터 예제이기 때문에 초기값을 0으로 설정한 것을 확인할 수 있습니다.
2) name: createSlice()를 통해 slice를 생성하게 되는데, 내부적으로 중복을 피하기 위해서 사용되는 고유한 값입니다.
3) reducers: 상태 변화를 처리하는 함수를 정의합니다. 함수의 이름은 dispatch로 부르는 액션 함수의 이름이며, 함수 내부는 위와 같이 state의 상태 값을 변경하는 처리를 해줍니다. dispatch에 포함해서 전달한 값은 PayloadAction<>의 타입의 action.payload 값으로 확인할 수 있습니다.
기존의 Redux에서 액션 타입을 지정하고, 타입에 따른 액션 생성함수, action.type에 따른 상태 변화 처리 및 불변성 처리를 3단계에 나눠서 했었다면, Redux Toolkit에서는 이 하나의 함수를 정의하는 것으로 끝납니다!
4) 후처리: createSlice로 생성된 counterSlice의 actions를 export시켜 외부에서 action을 호출할 수 있게 합니다. reducer 또한 export시켜 추후에 store에 리듀서를 등록할 수 있도록 노출시켜 줍니다.
3-2. configureStore()
/store/store.ts
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from '../store/counterSlice'
export const store = configureStore({
reducer: {
counter: counterReducer,
},
})
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
3-1에서 내보낸 reducer를 configureStore에 등록시켜 줍니다. 추후에 App에서 state.counter.value를 사용해 store에 저장된 리듀서의 값을 가져올 수 있습니다.
3-3. App 전역 Provider에 등록
// index.tsx
import {Provider} from "react-redux"
import {store} from './store/store'
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
위에서 작성한 store를 전역에서 사용할 수 있도록 React의 App 시작점에 Provider로 등록을 해줍니다.
3-4. Store 호출
import React from 'react'
import type { RootState } from '../../app/store'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './store/counterSlice'
export function Counter() {
const count = useSelector((state: RootState) => state.counter.value)
const dispatch = useDispatch()
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={() => dispatch(increment())}
>
Increment
</button>
<span>{count}</span>
<button
aria-label="Decrement value"
onClick={() => dispatch(decrement())}
>
Decrement
</button>
</div>
</div>
)
}
useSelector Hooks를 이용해 store에 저장된 state를 가져오고, useDispatch를 사용해 변경할 값을 reducer에 전달해줍니다.
일반 Redux보다 Redux Toolkit으로 사용한 코드가 훨씬 더 직관적입니다!
4. 온라인에서 실제로 해보기
https://codesandbox.io/s/github/reduxjs/redux-essentials-counter-example/tree/master/?from-embed
'FrontEnd > React 심화' 카테고리의 다른 글
[React] SSR과 CSR(SPA) 차이 (0) | 2022.10.19 |
---|---|
[React] Redux Toolkit 에서의 비동기 처리(createAsyncThunk, extraReducers) (0) | 2022.09.19 |
[React] Redux 사용하기(2) - 카운터 구현 (0) | 2022.06.21 |
[React] Redux 사용하기(1) - 개념과 흐름 (0) | 2022.06.21 |
[React] Immer (produce) (0) | 2022.04.04 |