전역 상태를 효율적으로 관리하기 위해 고민했던 내용들을 정리해보았습니다.
간단하게 Redux toolkit은,
Store를 설정
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
reducer: {
counter: counterReducer,
}
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
Provider 생성
import React, {useEffect} from 'react';
import Router from '@Router';
import {store} from '@app/store';
import {Provider} from 'react-redux';
const App = () => {
return (
<Provider store={store}>
<Router />
</Provider>
)
}
export default App;
Slice 생성
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
export interface CounterState {
value: number
}
const initialState: CounterState = {
value: 0,
}
export const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1
},
decrement: (state) => {
state.value -= 1
},
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload
},
},
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
리듀서 및 액션을 연결
import React from 'react'
import type { RootState } from '../../app/store'
import { useSelector, useDispatch } from 'react-redux'
import { decrement, increment } from './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>
)
}
와 같이 사용하게 된다.
나는 전역상태 관리를 Redux Toolkit으로 처음 시작했는데 그 때 이런식으로 작성했다.(사라져버린 코드라 임의로 작성;;)
slice
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
export interface DataState {
data1: string;
data2: string;
data3: string;
}
const initialState: DataState = {
data1: "",
data2: "",
data3: "",
}
export const dataSlice = createSlice({
name: 'data',
initialState,
reducers: {
setData: (state, action: PayloadAction<DataState>) => {
state = action.payload
},
},
})
export const { setData } = dataSlice.actions
export default dataSlice.reducer
사용
const App = () => {
const data = useSelector((state: RootState) => state.data)
const dispatch = useDispatch()
return (
<div>
<button
aria-label="데이터 전체 바꾸기"
onClick={() => dispatch(setData({
data1:"데이터1",
data2:"데이터2",
data3:"데이터3",
}))}
>
데이터 전체 바꾸기
</button>
<button
aria-label="데이터 일부 바꾸기"
onClick={() => dispatch(setData({
...data, data2:"data2",
}))}
>
데이터 일부 바꾸기
</button>
<button
aria-label="데이터 리셋"
onClick={() => dispatch(setData({
data1:"",
data2:"",
data3:"",
}))}
>
데이터 리셋
</button>
</div>
)
}
export default App;
이렇게 작성을 해서 Redux Toolkit을 사용했고 그 때는 하나의 함수로 여러가지 일을 모두 해낼수 있어서 그게 좋다고 생각하고 저렇게 사용했던것 같다;;
하지만 함수는 하나의 일을 해야 한다는 규칙이 있다.
그 외에도 여러가지 이유로 Reducer를 정의 하는 방법을 바꿔 사용했다.
그 이유는
이런 문제를 해결하기 위해 아래와 같이 수정하여 적용하였다.
slice
import { createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
export interface DataState {
data1: string;
data2: string;
data3: string;
}
interface PatchData {
key: keyof DataState;
value: string;
}
const initialState: DataState = {
data1: "",
data2: "",
data3: "",
}
export const dataSlice = createSlice({
name: 'data',
initialState,
reducers: {
putData: (state, action: PayloadAction<DataState>) => {
state = action.payload
},
patchData: (state, action: PayloadAction<PatchData>) => {
state[action.payload.key] = action.payload.value
},
resetData: (state) => {
state = initialState;
},
},
})
export const { putData, patchData, resetData } = dataSlice.actions
export default dataSlice.reducer
사용
const App = () => {
const dispatch = useDispatch()
return (
<div>
<button
aria-label="데이터 전체 바꾸기"
onClick={() => dispatch(putData({
data1:"데이터1",
data2:"데이터2",
data3:"데이터3",
}))}
>
데이터 전체 바꾸기
</button>
<button
aria-label="데이터 일부 바꾸기"
onClick={() => dispatch(patchData({
key: "data2",
value: "data2",
}))}
>
데이터 일부 바꾸기
</button>
<button
aria-label="데이터 리셋"
onClick={() => dispatch(resetData())}
>
데이터 리셋
</button>
</div>
)
}
export default App;
이렇게 하면 함수마다 하나의 일을 수행하고 있고,
함수명을 보고 어떤일을 하는지 알수 있고,
불필요한 데이터를 새로 생성하는일도 없어지고,
초기값을 알아야 되는 일도 없어지게 된다.
그리고 각 함수마다 하는 일을 알고 싶으면 정의된 slice 파일에 가서 한번에 전체적인 흐름을 파악할 수 있기 때문에 훨씬 가독성이 개선됐다고 느꼈다.
이 코드가 베스트라고 생각하진 않지만, 이렇게 이전에 개발했던 것들을 불편하다고 느낄 때 개선하고자 한다면 차츰차츰 발전해 나가는 코드를 작성할 수 있을거 같다.