- Published on
Redux-Toolkit
- Authors

- Name
- dwook
Table of Contents
설정
yarn add @reduxjs/toolkit
store/todo.ts
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { TodoType } from "../types/todo";
interface TodoReduxState {
todos: TodoType[];
}
//* 초기 상태
const initialState: TodoReduxState = {
todos: [],
};
const todo = createSlice({
name: "todo",
initialState,
reducers: {
//* 투두 변경하기
setTodo(state, action: PayloadAction<TodoType[]>) {
state.todos = action.payload;
},
},
});
// 다른 파일에서 디스패치할 때 사용하도록 export
export const todoActions = { ...todo.actions };
export default todo;
- redux-toolkit에서는 (1)액션타입 정의, (2)액션 생성자 정의하는 과정이 없어짐.
- createSlice가 리턴한 객체
- actions: 액션 생성자들.
todo.actions - caseReducers
- name
- reducer: combineReducers에
todo.reducer로 전달
- actions: 액션 생성자들.
- namer과 reducers의 속성이름으로 액션타입이 만들어짐.
todo/setTodo
store/index.ts
import {
TypedUseSelectorHook,
useSelector as useReduxSelector,
} from "react-redux";
import { HYDRATE, createWrapper } from "next-redux-wrapper";
import { configureStore, combineReducers } from "@reduxjs/toolkit";
import todo from "./todo";
const rootReducer = combineReducers({
todo: todo.reducer,
});
const reducer = (state, action) => {
if (action.type === HYDRATE) {
const nextState = {
...state,
...action.payload,
};
return nextState;
}
return rootReducer(state, action);
};
// * 스토어의 타입: 스토어의 타입을 rootReducer로 부터 얻는다.
export type RootState = ReturnType<typeof rootReducer>;
// * 타입 지원되는 커스텀 useSelector 만들기
export const useSelector: TypedUseSelectorHook<RootState> = useReduxSelector;
const initStore = () => {
return configureStore({
reducer,
devTools: true,
});
};
// App 컴퍼넌트에서 wrapper로 사용하기 위해 'next-redux-wrapper'에서 createWrapper를 import
export const wrapper = createWrapper(initStore);
- redux-toolkit은 데브툴을 포함하고 있어서 configureStore에서
devTools: true만으로 사용 가능
pages/index.tsx
import React from "react";
import { NextPage } from "next";
import TodoList from "../components/TodoList";
import { getTodosAPI } from "../lib/api/todo";
import { wrapper } from "../store";
import { todoActions } from "../store/todo";
const app: NextPage = () => {
return <TodoList />;
};
export const getServerSideProps = wrapper.getServerSideProps(
async ({ store }) => {
try {
const { data } = await getTodosAPI();
store.dispatch(todoActions.setTodo(data));
return { props: {} };
} catch (e) {
console.log(e);
return { props: {} };
}
}
);
export default app;
- 리덕스에 데이터를 저장하였기 때문에 페이지에 props를 전달하지 않아도 된다.
useSelector
- useSelector로 리덕스 스토어의 값을 가져옴.
- useSelector의 state 타입은 알 수 없으므로
RootState타입을 가져와서 지정. - 매번 RootState를 불러와서 타입을 지정하는 것은 번거로움.
1. useSelector에 타입을 지원하지 않을 경우
components/TodoList.tsx
import { useSelector } from "react-redux";
import { RootState } from "../store";
const TodoList:React.FC = () => {
const todos = useSelector((state: RootState) => state.todo.todos);
}
2. useSelector에 타입을 지원하는 경우
- 방법1. 커스텀 useSelector를 만들면 'react-redux'가 아닌 'store'에서 useSelector를 import하여 사용.
store/index.ts
import {
TypedUseSelectorHook,
useSelector as useReduxSelector,
} from "react-redux";
// * 스토어의 타입: 스토어의 타입을 rootReducer로 부터 얻는다.
export type RootState = ReturnType<typeof rootReducer>;
// * 타입 지원되는 커스텀 useSelector 만들기
export const useSelector: TypedUseSelectorHook<RootState> = useReduxSelector;
- 방법2. RootState에 타입지원
store/index.ts
declare module 'react-redux' {
interface DefaultRootState extends RootState {}
}
components/TodoList.tsx
import { useSelector } from "../store";
const TodoList:React.FC = () => {
const todos = useSelector((state) => state.todo.todos);
}
useDispatch
import { useSelector } from "../store";
import { useDispatch } from "react-redux";
import { todoActions } from "../store/todo";
const TodoList: React.FC = () => {
const todos = useSelector((state) => state.todo.todos);
const dispatch = useDispatch();
dispatch(todoActions.setTodo(newTodos));
}
참조링크