Redux Toolkit (+TypeScript) 세팅 방법에 대해 정리해보겠습니다
회사에서 프로젝트를 진행하던 중 Redux를 통해 state를 관리하기 위해 세팅해보기로 했다.
개인 프로젝트를 진행할 때 Redux Toolkit에 편리함을 느꼈어서 해당 툴을 사용하고자 했다.
📌 Redux Toolkit ?
- Redux Toolkit은 Redux를 만든 곳에서 공식적으로 효율적인 Redux 개발을 위해 만들어진 툴킷이다.
- Redux보다 코드가 간결하고 더 개선되어 유지 관리가 쉽기 때문에 사용을 강력히 권장하고 있다.
📌 Redux Toolkit이 제공하는 것
| store.js
import { configureStore, createSlice } from '@reduxjs/toolkit';
// news: 뉴스 데이터 (ajax요청)
let news = createSlice({
name : 'news',
initialState : {
loading : 'first',
data : [],
},
reducers : {
newsData(state, action){ // news 데이터 셋팅
if (state.loading === 'first'){
state.data = action.payload;
state.loading = 'second'
}
},
newsIdSet(state, action){ // detail page를 위한 id값 셋팅
if (state.loading === 'second'){
action.payload.map((a,val) => action.payload[val].source.id = val);
state.data = action.payload;
}
},
},
});
export default configureStore({
reducer: {
news : news.reducer
}
});
export let { newsData, newsIdSet } = news.actions;
위의 코드는 개인 프로젝트를 진행할 때 작성한 것이다. 코드를 한 줄씩 살펴보며 분석해보자
createSlice
: 자동으로 action type, action creator, reducer를 한 번에 생성함 (createAction
+createReducer
)
→ 위 코드에서 createSlice는 newsData, newsIdSet 이라는 action creator 와, 이에 대응하는 reducer 함수를 한번에 생성한다. 따라서 action type 을 따로 정의하거나, switch-case 문을 사용하여 reducer 를 작성할 필요가 없다.- state 수정시 사본 만들 필요 없음 (알아서 사본이 만들어짐 = 직접 수정 가능)
configureStore
: configureStore의 object를 ReduxcombineReducers
utility에 넘겨, 자동으로 root reducer를 생성함combineReducers
: 서로 다른 reducing function을 가진 object를 하나의 reducing function으로 바꾸도록 돕는 함수 → 위에서 configureStore를 사용했으면 combineReducers를 사용할 필요가 없다)
| store 사용하기 (MainNews.js)
import { useDispatch, useSelector } from "react-redux";
import { newsData, newsIdSet } from "../store.js";
const MainNews = () => {
let dispatch = useDispatch();
let news = useSelector(state => state.news.data); // 뉴스(redux)
// useEffect: 페이지가 렌더링되면 뉴스 데이터를 불러오기(axios)
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.get(~);
const JsonData = res.data.articles;
dispatch(newsData(JsonData)); // redux로 결과 전달
dispatch(newsIdSet(JsonData)); // redux로 결과 전달
}
catch (err){
console.log('오류가 발생했습니다.');
}
}
fetchData();
},[category]);
return (
<></>
)
}
useSelector
: parameter로 들어가는 state는 store에 있던 모든 state를 의미함useDispatch
: 사용할 action 함수를 import 해온 다음, dispatch로 action 함수를 감쌈 (* action 함수에 parameter로 전달된 값은 action.payload로 표현됨)
📌 Redux Toolkit (+ TypeScript ver.)
| store.ts
import { configureStore, createSlice } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
// PayloadAction = action.payload 필드의 타입을 지정할 수 있게 해주는 제네릭이다.
interface CounterState {
value: number
}
const initialState: CounterState = { value: 0 }
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment(state) {
// 첫번째 파라미터인 state는 타입지정 필요없음 (초기값에서 지정한 것이 자동으로 반영됨)
// return 타입지정 필요없음
state.value++
},
decrement(state) {
state.value--
},
incrementByAmount(state, action: PayloadAction<number>) {
state.value += action.payload
},
},
})
let store = configureStore({
reducer: {
counter : counterSlice.reducer
}
})
// store의 타입 미리 export 해두기
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
export const { increment, decrement, incrementByAmount } = counterSlice.actions
- 타입 지정 대상 :
initialState
,action
,reducer return
| store 사용하기 (App.tsx)
import { useDispatch, useSelector } from 'react-redux'
import { RootState, AppDispatch, increment } from './store.ts'
// import { Dispatch } from 'redux'
function App() {
const 꺼내온거 = useSelector((state: RootState) => state);
const dispatch = useDispatch<AppDispatch>();
// const dispatch: Dispatch = useDispatch();
return (
<div className="App">
{꺼내온거.counter.value}
<button onClick={() => {dispatch(increment())}}>버튼</button>
</div>
);
}
RootState
: reducer 만든 곳(=store)에서 미리 RootState라는 타입을 export 해두면, import해서 쉽게 타입 지정 가능AppDispatch
: dispatch 타입 가져옴
참고 :
https://redux.js.org/redux-toolkit/overview/
https://redux-toolkit.js.org/usage/usage-with-typescript
728x90
'배움 기록 > React' 카테고리의 다른 글
[React] Redux-persist 사용법(Redux toolkit ver.) (+ Next.js, TypeScript) (0) | 2023.05.30 |
---|---|
[React] useMemo와 useCallback 개념 정리 (+ 리렌더링, 메모이제이션, useEffect ...) (0) | 2023.03.05 |
[React] forwardRef 사용법 (useRef, useImperativeHandle...) (0) | 2023.02.05 |
[React] useEffect 총정리 (0) | 2023.01.08 |
댓글