리덕스 툴킷 기본 설계
먼저 reduxtk 폴더를 생성후 먼저 wordSlice.tsx 파일을 만들어준다.
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'
import wordApi from '../api/wordApi'
export interface IWords{
id: number,
word: string,
description: string,
example: string,
}
// Define a type for the slice state
export type Word = {
word: Array<IWords>,
}
// Define the initial state using that type
const initialState: Word = {
word: []
}
export const fetchUserById = createAsyncThunk(
'word/GET',
async (path: string) => {
return wordApi
.get(path)
.then((res) => res.data)
.catch((error) => error)
}
)
export const wordSlice = createSlice({
name: 'word',
// `createSlice` will infer the state type from the `initialState` argument
initialState,
reducers: {
ADD: (state, action: PayloadAction<IWords>) => {
console.log(action.payload)
state.word.push(action.payload)
},
UPDATE: (state, action: PayloadAction<IWords>) => {
if (action.payload.id !== undefined && action.payload.id !== null) {
state.word.map((v) => {
if (action.payload.id === v.id) {
return state.word[v.id] = { ...action.payload }
} else {
return v
}
})
}
},
DEL: (state, action: PayloadAction<number>) => {
state.word = state.word.filter(v => {
return v.id !== action.payload
})
}
},
extraReducers: (builder) => {
// Add reducers for additional action types here, and handle loading state as needed
builder
.addCase(fetchUserById.fulfilled, (state, action) => {
// Add user to the state array
state.word.push(...action.payload)
})
},
});
export const { ADD, DEL ,UPDATE} = wordSlice.actions
export default wordSlice.reducer
다음으로 store.tsx 를 만들어준다.
import { configureStore } from '@reduxjs/toolkit'
import wordSlice from './wordSlice'
import wordApi from '../api/wordApi'
// ...
export const store = configureStore({
reducer: wordSlice,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
thunk: {
extraArgument: wordApi,
},
serializableCheck: false,
}),
})
// 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
다음 사용할 커스텀 훅을 만들어 준다.
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
굳이 이렇게 커스텀 훅을 만들어주는 이유는
사용할떄마다 타입을 지정해주기 귀찮기 떄문이다.
리덕스 툴킷 작동 방식(개인적인 생각)
아직 자세히 알아보지않았지만 사용하면서 작동 방식에대해 생각해봤다 .
먼저 나는 처음에 api 의 데이터를 가져오기 위해서
wordSlice 안에 있는 fetchUserById 라는 createAsyncThunk 로 만든 함수를 디스패치 시켰다 .
해당 함수를 디스패치 시키면
해당 함수가 실행되고 상태값을 반황한다 이때 가지는 상태 값은
pending , fulfilled, rejected
이렇게 3가지가 있다
느낌상 왼쪽부터 준비 완료 실패 인것 같다.
해당 값을 리턴 받으면 wordSlice 안에 extraReducers 의 케이스를 검사해서 해당 케이스를 실행 시킨다.
또 reducers 에 추가한 액션들은
내가 따로 지정 해주지 않아도 그냥 이름을 적는대로 추가가 된다.
실행방법은
const wordLists = useAppSelector((state) => state.word)
const addWords = useCallback(
(word: IWords) => dispatch(ADD(word)),
[dispatch]
);
addWords(inputData);
위같은 방법으로 실행방법은 그냥 리덕스와 똑같다.