[React] RTK(Redux Toolkit)[작성중]
먼저 [Redux↗️]에 대해 알고 오자!
1. 개요
1.1 RTK란?
Redux Toolkit (RTK)은 Redux를 더 쉽게 사용하고 복잡성을 줄이기 위해 만들어진 라이브러리이다.
1.2 RTK 사용 이유
- 간결한 코드: RTK는 createSlice, configureStore 등의 유틸리티를 통해 보일러플레이트 코드를 줄여줘 개발자가 애플리케이션의 실제 로직에 더 집중할 수 있게 해준다.
- 미들웨어 및 DevTools 설정 자동화: configureStore는 Redux DevTools와 기본 미들웨어 설정을 자동으로 처리해준다.
- 비동기 작업 간소화: createAsyncThunk는 비동기 작업의 상태를 쉽게 관리할 수 있도록 도와준다.
1.3 설치
yarn add @reduxjs/toolkit react-redux
2. RTK 시작하기
2.1 Create a Redux Store
src/app/store.js
import { configureStore } from "@reduxjs/toolkit";
export default configureStore({
reducer: {},
});
2.2 Provide the Redux Store to React
src/index.js
에서 React에게 Redux Store를 제공해주자
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import store from "./app/store";
import { Provider } from "react-redux";
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
2.3 Create a Redux State Slice
src/features/todo/todoSlice.js.js
에서 createSlice
를 만들자
import { createSlice } from "@reduxjs/toolkit";
export const todoSlice = createSlice({
name: "todo",
initialState: {
todos: [],
},
});
export default todoSlice.reducer;
2.4 Add Slice Reducers to the Store
src/index.js
에서 reducer
import { configureStore } from "@reduxjs/toolkit";
import todoReducer from "../features/todo/todoSlice";
export default configureStore({
reducer: {
todo: todoReducer,
},
});
2.5 Use Redux State and Actions in React Components
아래 코드는 외우는 것이 좋다!
3. RTK 메서드
3.1 configureStore
- 목적: Redux 스토어의 설정과 생성을 간소화한다.
- 특징:
configureStore
는 미들웨어와 Redux DevTools를 자동으로 설정해준다.
import { configureStore } from "@reduxjs/toolkit";
import rootReducer from "./reducers";
// configureStore를 사용하여 Redux 스토어를 설정하고 생성한다.
// 이 함수는 Redux DevTools 및 Thunk 미들웨어를 자동으로 활성화한다.
const store = configureStore({
// rootReducer를 통해 여러 리듀서를 하나로 합친다.
reducer: rootReducer,
// 추가 설정이 필요한 경우, 여기에 다른 옵션들을 지정할 수 있다.
});
3.2 createSlice
- 목적: 액션 타입, 액션 생성자, 리듀서 함수를 한 번에 생성한다.
- 특징:
createSlice
는 이름, 초기 상태, 리듀서 함수를 객체 형태로 받아, 액션 생성자와 액션 타입을 자동으로 생성한다. 또한 lmmer 라이브러리를 내장하고 있어, 상태 업데이트 로직을 불변성을 유지하면서 간결하게 작성할 수 있다.
import { createSlice } from "@reduxjs/toolkit";
// ceateSlice를 사용하여 todos에 대한 리듀서와 액션 생성자를 한 번에 정의한다.
const todoSlice = createSlice({
name: "todos", // 슬라이스의 이름, 생성되는 액션 타입의 접두사로 사용
initialState: [], // 상태의 초기값을 설정
reducers: {
// 리듀서 로직과 액션들을 정의
// todo 항목을 추가하는 리듀서.
// 액션의 payload를 현재 상태에 직접 push. Immer 덕분에 불변성을 신경쓰지 않아도 됨
addTodo: (state, action) => {
state.push(action.payload);
},
// todo 항목을 제거하는 리듀서
// 액션의 payload로 전달된 id와 일치하지 않는 항목만 필터링하여 새 배열을 반환
removeTodo: (state, action) => {
return state.filter((todo) => todo.id !== action.payload);
// const targetIndex = findIndex((todo) => todo.id === action.payload);
// state.splice(targetIndex, 1);
},
},
});
// 생성된 액션 생성자 함수와 리듀서를 각각 내보냄
export const { addTodo, removeTodo } = todoSlice.actions;
export default todoSlice.reducer;
3.3 createAsyncThunk
- 목적: 비동기 로직을 처리하기 위한 Thunk 함수를 생성
- 특징:
createAsyncThunk
는 비동기 함수를 인자로 받고, 해당 비동기 함수의 실행 결과에 따라 “pending”, “fulfilled”, “rejected” 상태의 액션을 자동으로 디스패치한다. 이를 통해 비동기 로직을 쉽게 Redux 스토어와 연동할 수 있다.
import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
// createAsyncThunk를 사용하여 비동기적으로 todos를 불러오는 Thunk 액션 생성자를 정의한다.
// "todos/fetchTodos"는 생성될 액션 타입의 접두사로 사용된다.
export const fetchTodos = createAsyncThunk("todos/fetchTodos", async () => {
// axios를 사용해 비동기적으로 데이터를 가져온다.
const response = await axios.get("https://api.example.com/todos");
// 응답 데이터를 Thunk의 반환값으로 지정한다. 이 값은 리듀서에서 처리된다.
return response.data;
});
3.4 extraReducer
- 목적:
createAsyncThunk
로 정의한 함수를 사용하는 방법 - 특징:
createSlice
내에서 비동기 액션의 결과(상태)를 다룰 수 있다.
import { createSlice } from "@reduxjs/toolkit";
import { fetchTodos } from "./fetchTodos"; // 비동기 액션 생성자를 임포트한다.
const todosSlice = createSlice({
name: "todos",
initialState: {
items: [], // 실제 todo 항목들을 저장할 배열
status: "idle", // "idle", "loading", "succeeded", "failed"
error: null, // 요청 실패 시 에러 메시지 저장
},
reducers: {
// 일반 동기 액션 핸들러들을 정의할 수 있다.
},
extraReducers: (builder) => {
builder
.addCase(fetchTodos.pending, (state) => {
// 비동기 요청이 시작될 때 상태를 업데이트한다.
state.status = "loading";
})
.addCase(fetchTodos.fulfilled, (state, action) => {
// 요청이 성공적으로 완료됐을 때 상태를 업데이트한다.
state.status = "succeeded";
// 불러온 todos를 상태에 추가한다.
state.items = action.payload;
})
.addCase(fetchTodos.rejected, (state, action) => {
// 요청이 실패했을 때 상태를 업데이트한다.
state.status = "failed";
state.error = action.error.message;
});
},
});
export default todosSlice.reducer;
댓글남기기