[React 심화] Redux Thunk

Habin Lee·2023년 12월 4일
1

요약

  • Redux 구조에서 비동기를 다루는 기술(미들웨어)인 Thunk에 대해 알고 사용할 수 있다.

Redux 미들웨어

  • 리덕스: dispatch -> action -> 리듀서 -> 새로운 state 반환
  • 액션 - > 미들웨어 -> 리듀서 -> 스토어
    ※ 미들웨어를 사용하면 리덕스 과정 사이에 우리가 하고 싶은 작업들을 넣어서 할 수 있다.
  • 리덕스 미들웨어를 사용하는 이유: 서버와의 통신을 위해 사용하는 것이 대부분!
    -> 그 중 많이 사용되고 있는 리덕스 미들웨어가 Redux-thunk

thunk

  • thunk를 사용하면 우리가 dispatch를 할 때 객체가 아닌 함수를 dispatch 할 수 있게 해준다. 즉, dispatch(객체)가 아니라 dispatch(함수)를 할 수 있게 되는 것이다.
  • dispatch(함수) → 함수실행 → 함수안에서 dispatch(객체)
  • thunk는 Redux 설정을 모두 한 후에 작성하면 된다.

thunk 함수 만들어보기

  • 카운트앱에 setTimeout 기능을 넣어보자.
  • redux-toolkit 에서 createAsyncThunk 라는 API를 사용하여 thunk 함수를 생성
    -> 첫 번째 인자: Action value, 두 번째 인자: 함수(여기서 하고 싶은 작업 구현)
  • thunk 이름 앞에 __ (언더바 2개)를 붙여 thunk 함수라는 것을 표시해주면 좋다.
    -> 하지만 개인의 규칙이므로 이름은 본인이 편한대로 명명해도 된다.
  • 아래는 thunk 함수를 구현하기 위해 틀을 잡아보았다.
export const __addNumber = createAsyncThunk(
	"ADD_NUMBER_WAIT",
	(arg, thunkAPI)=>{},
);
  • 여기에 3초를 기다리게 하는 함수를 넣어보자

counterSlice.js

// createAsyncThunk import
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
// 언더바 2개를 붙인 thunk 함수 만들기
export const __addNumber = createAsyncThunk(
  // 첫번째 인자 : action value
  "addNumber", 
  // 두번째 인자 : 콜백함수(내가 구현하고 싶은 함수-setTimeout)
  (payload, thunkAPI) => {
    setTimeout(() => {
      thunkAPI.dispatch(addNumber(payload));
    }, 3000);
  }
);
// 초기값 설정
const initialState = {
  number: 0,
};
// Redux toolkit
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;
    },
  },
});
// reducer와 actions export
export const { addNumber, minusNumber } = counterSlice.actions;
export default counterSlice.reducer;
  • 두번째로 들어가는 함수에서 2개의 인자를 꺼내 사용할 수 있는데, 첫번째 인자는 컴포넌트에서 보내준 payload이고, 두번째 인자는 thunk에서 제공하는 여러가지 기능이다.
  • dispatch: thunk 함수안에서 dispatch를 할 때 사용
  • getState: thunk 함수안에서 현재 리덕스 모듈의 state 값을 사용하고 싶을 때 사용

App.jsx

import React from "react";
import { useState } from "react";
// useDispatch, useSelector, minusNumber, __addNumber import
import { useDispatch, useSelector } from "react-redux";
import { minusNumber, __addNumber } from "./redux/modules/counterSlice";

const App = () => {
  // useDispatch, useState, useSelector 선언
  const dispatch = useDispatch();
  const [number, setNumber] = useState(0);
  const globalNumber = useSelector((state) => state.counter.number);
  // onchange - value
  const onChangeHandler = (evnet) => {
    const { value } = evnet.target;
    setNumber(+value);
  };

  const onClickAddNumberHandler = () => {
    // thunk 함수를 dispatch(더할 때 3초를 기다리게 하는 함수)
    // thunk함수에 payload를 넣어주면 redudx module에서 payload를 받을 수 있다.
    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초 기다렸다가 더하기 카운터가 동작하는 것을 확인할 수 있다.

0개의 댓글