가수면
[Redux] Redux ToolKit thunk 본문
thunk
미들 웨어 비동기 처리. dispatch 를 할 때 객체가 아닌 함수를 dispatch할 수 있게 해줌.
thunk 사용하기
간단한 예제)
// src/redux/modules/counterSlice.js
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
export const __addNumber = createAsyncThunk(
// 첫번째 인자 : action value
"addNumber",
// 두번째 인자 : 콜백함수
(payload, thunkAPI) => {
setTimeout(() => {
thunkAPI.dispatch(addNumber(payload));
}, 3000);
}
);
이후 App.js의 액션 크리에이터 addNumber를 __addNumber로 수정하면 적용 완료.
const initialState = {
todos: [],
isLoading: false,
error: null,
};
//createAsyncThunk는 비동기 작업을 처리하는 action을 만들어준다.
export const __getTodos = createAsyncThunk(
"getTodos",
async (payload, thunkAPI) => {
// try / catch문을 사용해서 여기에서 실패했을 경우 에러를 콘솔로 찍어라.
try {
const data = await axios.get("http://localhost:3001/todos")
console.log(data);
} catch (error) {
console.log(error);
}
}
)
// src/App.jsx
import React, { useEffect } from "react";
import { useDispatch } from "react-redux";
import { __getTodos } from "./redux/modules/todosSlice";
const App = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(__getTodos());
}, [dispatch]);
return <div>App</div>;
};
export default App;
fullfillWithValue / rejectWithValue
fullfillWithValue - 네트워크 요청이 성공한 경우에 dispatch해주는 기능
rejectWithValue - 네트워크 요청이 실패한 경우 dispatch해주는 기능
앞의 __붙이는 것은 thunk 함수에 사용될 녀석이라는 일종의 약속이다.
//기본 형태
export const __changeTodos = createAsyncThunk(
"CHANGE_TODO",
async (todo, thunkApi) => {
try {
await axios.patch(`http://localhost:3001/todos/${todo.id}`, { state: !todo.state })
return thunkApi.fulfillWithValue(todo)
} catch (error) {
return thunkApi.rejectWithValue(error)
}
}
)
extraReducer 추가
thunk함수는 reducer가 아니라 외부에서 작성된 것이기 때문에 extraReducer라는 메소드를 사용해야 된다. (switch 조건문이라고 보면 됨)
리덕스 툴 킷의 2.0 버전에서 객체 표기법이 제거될 예정이다.
'builder callback' 표기법을 사용하도록 하자.
const todoSlice = createSlice({
name: "todos",
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(__changeTodos.pending, (state) => {
state.isLoading = true;
})
.addCase(__changeTodos.fulfilled, (state, action) => {
state.isLoading = false;
state.todos = state.todos.map((todo) => (todo.id === action.payload.id ? { ...todo, state: !todo.state } : todo));
})
.addCase(__changeTodos.rejected, (state, action) => {
state.isLoading = false;
state.error = action.payload;
})
심화
심화 (1)
await의 http://localhost:3001/todos/${todo.id}로 가보면 지정한 녀석의 데이터 가 있는 것을 확인할 수 있다.
뒤에 쉼표 붙이고 객체로 오는 { state: !todo.state }는 그 페이지 데이터의 state를 dispatch로 가져온 todo를 활용해 바꾸겠다는 얘기다. (결국 초기 API짤 때 지정했었던 내용이 들어가야 한다는 것.)
export const __changeTodos = createAsyncThunk(
"CHANGE_TODO",
async (todo, thunkApi) => {
try {
await axios.patch(`http://localhost:3001/todos/${todo.id}`, { state: !todo.state })
return thunkApi.fulfillWithValue(todo)
} catch (error) {
return thunkApi.rejectWithValue(error)
}
}
)
심화(2)
export const __detailTodos = createAsyncThunk(
"DETAIL_TODO",
async (id, thunkApi) => {
try {
const detail = await axios.get(`http://localhost:3001/todos/${id}`)
return thunkApi.fulfillWithValue(detail.data);
} catch (error) {
return thunkApi.rejectWithValue(error)
}
}
)
만일 위 코드를 fulfillWithValue(detail)로 바꿀 경우 action과 state는 직렬화할 수 없는 데이터를 받지 않는다며 오류가 뜬다. (a non-serializable value was detected in an action...)
먼저 직렬화라는 개념을 알아보자.
컴퓨터 메모리 상에 존재하는 객체(Object) -> 문자열(string) 로 변환하는 것
= 직렬화(Serialization)
즉, 우리는 아래처럼 바꿀 수 있는 데이터를 action으로 넘겨줘야만 한다는 얘기다.
{
"name" : "Alice",
"age" : 27,
"gender" : "male",
"location" : "Incheon",
"marriage" : false,
"friends" : ["Lee","Shin","Jang"]
}
이는 로컬 스토리지에서 setItem을 JSON.stringify()로 바꾸고 getItem을 해줄 때 JSON.parse()로 바꿔주는 것과 같은 원리로 보인다.
export const getLocal = () => {
return JSON.parse(localStorage.getItem('todolist'))
}
export const setLocal = (todo) => {
localStorage.setItem('todolist', JSON.stringify(todo))
}
따라서 fulfillWithValue의 값을 const detail안에 있는 data를 지정해 넘겨줘야만 한다.
'React > 라이브러리' 카테고리의 다른 글
[Styled Components] Styled Components 심화 (0) | 2022.12.19 |
---|---|
[Styled Components] Styled Components Global Style (0) | 2022.12.17 |
[Redux] Redux ToolKit (0) | 2022.12.09 |
Router (0) | 2022.12.03 |
[Styled Components] Styled Components (0) | 2022.12.02 |