1. Redux 미들웨어
(1) 미들웨어란?
리덕스에서 dispatch를 하면 action 이 리듀서로 전달이 되고, 리듀서는 새로운 state를 반환합니다. 근데 미들웨어를 사용하면 이 과정 사이에 하고 싶은 작업들을 넣어서 할 수 있습니다.
만약 counter 프로그램에서 더하기 버튼을 클릭했을 때 바로 +1를 더하지 않고 3초를 기다렸다가, +1이 되도록 구현하려면 미들웨어를 사용하지 않고서는 구현할 수 없습니다.
왜냐하면 dispatch가 되자마자 바로 action이 리듀서로 달려가서 새로운 state를 반환해버리기 때문이죠. 즉 여기서 “3초를 기다리는 작업" 이 작업을 미들웨어가 해주는 것 입니다.
보통 리덕스 미들웨어를 사용하는 이유는 서버와의 통신을 위해서 사용하는 것이 대부분이고, 또한 그 중에서도 많이 사용되고 있는 리덕스 미들웨어는 Redux-thunk 라는 것이 있습니다.
2. thunk
(1) thunk 소개
리덕스 thunk란,
리덕스에서 많이 사용하고 있는 미들웨어중에 하나입니다. thunk를 사용하면 dispatch를 할때 객체가 아닌 함수를 dispatch 할 수 있게 해줍니다. 즉 dispatch(객체) 가 아니라 dispatch(함수)를 할 수 있게 되는 것이죠!
그래서 중간에 하고자 하는 작업을 함수를 통해 넣을 수 있고, 그것이 중간에 실행이 되는 것 입니다. 그래서 아래 흐름과 같이 실행이 되는거죠. 그리고 이 함수를 thunk 함수라고 부릅니다.
dispatch(함수) → 함수실행 → 함수안에서 dispatch(객체)
(2) thunk 사용하기
아래 순서대로 구현을 할 것 입니다.
- thunk 함수 만들기
- extraReducer에 thunk 등록하기
- dispatch(thunk 함수) 하기
- 테스트
(3) thunk 함수
thunk 함수를 만들어봅시다.
thunk 함수의 역할은 “3초를 기다리는 것” 입니다. 그리고 3초가 지나면 원래 하려고 했던 ADD_NUMBER를 해주는 것 까지가 thunk함수가 해야 할 일 입니다.
툴킷에서는 createAsyncThunk 라는 API를 사용해서 thunk 함수를 생성할 수 있습니다. 이 API는 함수인데, 첫번째 인자에는 Action Value, 두번째 인자에는 함수가 들어갑니다. 이 함수에 하고 싶은 작업들을 구현하면 됩니다.
두번째 들어가는 함수에서도 인자를 꺼낼 수 있는데, 첫번째 인자(arg)는 이 thunk함수가 외부에서 사용되었을 때 넣은 값을 여기에서 조회할 수 있고, 두번째 인자에서는 thnuk가 제공하는 여러가지 API 기능들이 담긴 객체를 꺼낼 수 있습니다.
// thunk 함수는 createAsyncThunk 라는 툴킷 API를 사용해서 생성합니다.
// __가 함수 이름에 붙는 이유는 이 함수가 thunk 함수라는 것을 표시하기 위한
// 개인의 convention 입니다. 함수의 이름은 본인이 편한 이름으로 명명하세요.
export const __addNumber = createAsyncThunk(
"ADD_NUMBER_WAIT",
(arg, thunkAPI)=>{},
);
원래 하려고 했던 3초를 기다리는 thunk 함수를 만들어볼게요. 아래 코드를 참고해주세요. 첫번째 자리에는 action value를 넣었습니다. 그리고 두번째에는 함수를 넣었어요.
함수안에는 setTimeout 라는 Web API를 이용해서 3초를 기다리게 했고, 이후에 thunkAPI 안에 있는 dispatch를 통해서 원래 하려고 했던 addNumber라는 action creator를 넣었습니다.
코드 수정 : 생략했던 모듈 코드 추가, arg를 payload로 변경
// src/redux/modules/counterSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
export const __addNumber = createAsyncThunk(
// 첫번째 인자 : action value
"addNumber",
// 두번째 인자 : 콜백함수
(payload, thunkAPI) => {
setTimeout(() => {
thunkAPI.dispatch(addNumber(payload));
}, 3000);
}
);
const initialState = {
number: 0,
};
const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
addNumber: (state, action) => {
state.number = state.number + action.payload;
},
minusNumber: (state, action) => {
state.number = state.number - action.payload;
},
},
});
export const { addNumber, minusNumber } = counterSlice.actions;
export default counterSlice.reducer;
arg는 컴포넌트에서 사용자가 input에 입력한 더하고자 하는 값입니다. 예전에 구현했던 것인데요, 이런식으로 payload 값을 받아올 수 있습니다.
컴포넌트에서의 코드는 아래와 같습니다. 기존에는 addNumber 라는 action creator를 dispatch했다면, 이제는 __addNumber 라는 thunk함수를 dispatch 해줍니다.
App.jsx에 아래 코드를 작성해봅시다.
코드 수정 : 파일이름 수정 counter → counterSlice
// src/App.jsx
import React from "react";
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { minusNumber, __addNumber } from "./redux/modules/counterSlice";
const App = () => {
const dispatch = useDispatch();
const [number, setNumber] = useState(0);
const globalNumber = useSelector((state) => state.counter.number);
const onChangeHandler = (evnet) => {
const { value } = evnet.target;
setNumber(+value);
};
// thunk 함수를 디스패치한다. payload는 thunk함수에 넣어주면,
// 리덕스 모듈에서 payload로 받을 수 있다.
const onClickAddNumberHandler = () => {
dispatch(__addNumber(number));
};
const onClickMinusNumberHandler = () => {
dispatch(minusNumber(number));
};
return (
<div>
<div>{globalNumber}</div>
<input type="number" onChange={onChangeHandler} />
<button onClick={onClickAddNumberHandler}>더하기</button>
<button onClick={onClickMinusNumberHandler}>빼기</button>
</div>
);
};
export default App;
3. 정리
- 리덕스 미들웨어를 사용하면, 액션이 리듀서로 전달되기전에 중간에 어떤 작업을 더 할 수있다.
- Thunk를 사용하면, 객체가 아닌 함수를 dispatch 할 수 있게 해준다. [thunk의 핵심]
- 리덕스 툴킷에서 Thunk 함수를 생성할 때는 createAsyncThunk 를 이용한다.
- createAsyncThunk() 의 첫번째 자리에는 action value, 두번째에는 함수가 들어간다.
- 두번째로 들어가는 함수에서 2개의 인자를 꺼내 사용할 수 있는데, 첫번째 인자는 컴포넌트에서 보내준 payload이고, 두번째 인자는 thunk에서 제공하는 여러가지 기능이다.
- dispatch: thunk 함수안에서 dispatch를 할 때 사용
- getState: thunk 함수안에서 현재 리덕스 모듈의 state 값을 사용하고 싶을 때 사용
'React' 카테고리의 다른 글
React - Custom Hooks (0) | 2023.12.09 |
---|---|
React - Redux Thunk 자세히 다뤄보기 (1) | 2023.12.03 |
React - axios(instance & interceptor) (1) | 2023.11.30 |
React - 비동기 통신(axios & fetch) (0) | 2023.11.29 |
React - Redux Toolkit(feat. Redux Devtools) 사용하기 (1) | 2023.11.27 |