module/todos.js
- Redux toolkit 에서는 Thunk가 내장되어 있다.
createAsyncThunk
를 사용하고 redux-thunk
와 비슷하게 썽크함수 내부에서 dispatch
, getState()
가 가능하다.
- 특이한 점은, 이렇게 만들어진 썽크함수는
Slice
내에서 reducers
가 아닌, extraReducers
에서 동작하며, 비동기처리 상태 3단계가 자동으로 각각 dispatch
된다. (logger에도 각각 찍힌다 : pending
과 fullfilled
) 즉, 한번의 dispatch(__loadTodos())
호출로 대기, 이행, 실패 했을 때의 각각 후속작업을 진행 할 수 있다.
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { todoApi } from "../api";
export const __loadTodos = createAsyncThunk(
"todos/LOAD_TODOS",
async (params, { getState, dispatch }) => {
const { data } = await todoApi.loadTodos();
return data;
}
);
const todoSlice = createSlice({
name: "todos",
initialState: {
todos: {
loading: true,
error: {
status: false,
message: "",
},
data: [],
},
},
reducers: {
initTodos: (state) => (state.todos = { loading: true, data: [] }),
},
extraReducers: {
[__loadTodos.pending]: (state) => {
state.todos.loading = true;
},
[__loadTodos.fulfilled]: (state, { payload }) => {
state.todos.loading = false;
state.todos.data = payload;
},
[__loadTodos.rejected]: (state, { error }) => {
console.log(error);
state.todos.loading = false;
state.todos.error.status = true;
state.todos.error.message = error.message;
},
},
});
export const { initTodos } = todoSlice.actions;
export default todoSlice;
App.js
import { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { __loadTodos, initTodos } from "./module/todos";
function App() {
const dispatch = useDispatch();
const {
loading,
data: todos,
error,
} = useSelector((state) => state.todos.todos);
useEffect(() => {
dispatch(__loadTodos());
return () => initTodos();
}, []);
if (loading) return <div>로딩중...</div>;
if (error.status) return <div>{error.message}</div>;
return (
<div className="App">
{todos.map((todo) => (
<div key={todo.id}>{todo.title}</div>
))}
</div>
);
}
export default App;