Thunk

손유민·2024년 12월 13일

Redux 미들웨어

  • 미들웨어란?
    리덕스에서 dispatch하면 action이 리듀서로 전달되고, 리듀서는 새로운 state를 반환한다.
    미들웨어 사용시 이 과정 사이에 추가하고 싶은 작업들을 넣을 수 있다.
    counter 프로그램에서 더하기 버튼을 눌렀을 때 바로 +1을 더하지 않고 3초 기다렸다가 +1이 되도록 미들웨어를 사용해 구현할 수 있다.
    리덕스 미들웨어를 사용하는 이유는 서버와의 통신을 위해서 사용하는 것이 대부분이고, 또한 그 중에서도 많이 사용되고 있는 리덕스 미들웨어는 Redux-thunk이다.

Thunk

  • thunk 소개
    리덕스 thunk란
    리덕스에서 많이 사용하고 있는 미들웨어중 하나이다.
    thunk을 사용하면 dispatch를 할때 객체가 아닌 함수를 dispatch할 수 있게 해준다.
    즉 dispatch(객체)가 아니라 dispatch(함수)를 할 수 있게 된다.
    중간에 하고자 하는 작업을 함수를 통해 넣을 수 있고, 그것이 중간에 실행이 되는것이다.
    이 함수를 thunk함수 라고 한다.
dispatch(함수) -> 함수실행 -> 함수안에서 diuspatch(객체)
  • thunk 사용하기
    아래 순서대로 구현 할 것이다.
  1. thunk 함수 만들기
  2. extraReducer에 thunk 등록하기
  3. dispatch(thunk 함수) 하기
  4. 테스트

  • thunk 함수 만들기

createAsyncThunk api를 사용해 thunk 함수를 생성할 수 있다.
이 api는 첫번째 인자에 action value, 두번째 인자에 함수가 들어간다.
이 함수에 하고싶은 작업들을 구현하면 된다.

두번쨰 들어가는 함수에서도 인자를 꺼낼 수 있는데, 첫번째 인자(arg)는 이 thunk 함수ㅜ가 외부에서 사용되었을 때 넣은 값을 여기에서 조회할 수 있고, 두번째 인자에서는 thunk가 제공하는 여러가지 api 기능들이 담긴 객체를 꺼낼 수 있다.

// thunk 함수는 createAsyncThunk 라는 툴킷 API를 사용해서 생성

// __가 함수 이름에 붙는 이유는 이 함수가 thunk 함수라는 것을 표시하기 위한 
// 개인의 convention. 함수의 이름은 본인이 편한 이름으로 명명

export const __addNumber = createAsyncThunk(
	"ADD_NUMBER_WAIT",
	(arg, thunkAPI)=>{},
);

처음 예시로 했던 3초 기다렸다가 실행하는 함수를 만들어보자.

// 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;

함수안에 setTimeout web api를 이용해 3초 지연했다. 그 다음에 thunkAPI 안에 있는 dispatch를 통해 원래 하려고 했던 addNumber라는 action creator를 넣었다.

App.jsx 파일도 봐보자

// 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;

기존에 addNumber 라는 action creator를 dispatch 했다면, 이젠 __addNumber라는 thunk 함수를 dispatch 한다.


정리

  • 리덕스 미들웨어를 사용하면, 액션이 리듀서로 전달되기 전에 중간에 어떤 작업을 추가할 수 있다.
  • thunk를 사용하면, 객체가 아닌 함수를 dispatch할 수 있게 된다.
  • 리덕스 툴킷에서 thunk 함수를 생성할 때 createAsyncThunk를 이용한다.
  • createAsyncThunk()의 첫번째 자리에는 action value, 두번째에는 함수가 들어간다.
  • 두번째로 들어가는 함수에서 2개의 인자를 꺼내 사용할 수 있는데, 첫번째 인자는 컴포넌트에서 보내준 payload고, 두번째 인자는 thunk에서 제공하는 여러가지 기능이다.
  • dispatch: thunk 함수안에서 dispatch할 때 사용
  • getState: thunk 함수안에서 현재 리덕스 모듈의 state 값을 사용하고 싶을 때 사용
profile
프론트가 되고싶은 웹디자이너

0개의 댓글