[React] Redux-thunk

rang·2022년 8월 11일

React

목록 보기
5/5

Middleware in Redux

리덕스에서 dispatch를 하면 action이 reducer로 전달이 되고 reducer는 새로운 state를 반환한다. 미들웨어를 사용해 이 과정 사이에 추가하고 싶은 작업을 넣을 수 있다.

보통 비동기 작업을 하기 위해 미들웨어를 사용한다. 리덕스 미들웨어 라이브러리를 설치해 사용한다. 비동기 작업에 관련된 미들웨어 라이브러리는 redux-thunk, redux-saga, redux-observable, redux-promise-middleware 등이 있다.


thunk

thunk는 지연된 작업을 수항하는 코드 조각을 의미하는 프로그래밍 용어이다. 바로 일부 논리를 실행하는 대신 나중에 작업을 수행하는 데 사용할 수 있는 함수 본문이나 코드를 작성할 수 있다.

Redux에서 thunk는 redux store 및 메서드와 상화작용 할 수 있는 내부 논리가 있는 함수를 작성하는 패턴이다. redux에서 thunk를 사용하려면 redux-thunk 미들웨어 라이브러리를 추가해 사용할 수 있다. 동기 및 비동기 논리를 모두 포함하는 방법이다.

구현 방법

1. thunk 함수

  • thunk 함수 기본 구조
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";

export const fetchTodos = createAsyncThunk(
  "getTodos",
  (payload, thunkAPI) => {
    
  }
);

thunk로 서버에서 값을 가져오기
axios.get() 함수는 promise를 반환한다. 반환된 promise의 fulfilled 또는 rejected된 것을 처리하기 위해 비동기인 async/await를 추가하였다.

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import axios from "axios";

export const fetchTodos = createAsyncThunk(
  "getTodos",
  async (payload, thunkAPI) => {
    try {
      const response = await axios.get('http://localhost:3001/todos');
      return response.todos;
    } catch (err) {
      return err;
    }
  }
);

2. reducer

redux-toolkit으로 redux를 구현하였을때 createSlice() 내부의 reducer에서 액션 함수를 생성해야 하는데 redux-thunk를 사용한다면 extraRuducers 안에 액션 함수를 구현해야 한다.

pending: 네트워크 요청 시작 후 로딩 상태
fulfilled: 네트워크 요청 완료
rejected: 네트워크 요청 실패, 에러

  • Map Object 표기법
export const todosSlice = createSlice({
  name: "todos",
  initialState,
  reducers: {},
  extraReducers: {
    [fetTodos.pending]: (state) => {
      state.isLoading = true;
    },
    [fetTodos.fulfilled]: (state, action) => {
      state.isLoading = false;
      state.todos = action.payload;
    },
    [fetTodos.rejected]: (state, action) => {
      state.isLoading = false;
      state.error = action.payload;
    },
  },
});

  • Builder Callback 표기법
const todosSlice = createSlice({
  name: 'todos',
  initialState,
  reducers: {},
  extraReducers: builder => {
    builder
      .addCase(fetchTodos.pending, (state, action) => {
        state.status = 'loading';
      })
      .addCase(fetchTodos.fulfilled, (state, action) => {
        state.isLoading = false; // 네트워크 요청이 끝났으니, false로 변경합니다.
        state.todos = action.payload;
      })
  }
});

3. store 값 조회

dispatch로 store의 값을 조회한다.

import React, { useEffect } from "react";
import { useDispatch } from "react-redux";
import { fetchTodos } from "./redux/modules/todosSlice";

const App = () => {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(fetTodos());
  }, [dispatch]);

  return <div>App</div>;
};

export default App;



  • reducer 파일 전체 코드 - todosSlice.js
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import axios from "axios";

const initialState = {
  todos: [],
  isLoading: false,
  error: null,
};

export const fetchTodos = createAsyncThunk(
  "getTodos",
  async (payload, thunkAPI) => {
    try {
      const response = await axios.get('http://localhost:3001/api/todos');
      return response.todos;
    } catch (err) {
      return err;
    }
  }
);

export const todosSlice = createSlice({
  name: "todos",
  initialState,
  reducers: {},
  extraReducers: {
    [fetTodos.pending]: (state) => {
      state.isLoading = true;
    },
    [fetTodos.fulfilled]: (state, action) => {
      state.isLoading = false;
      state.todos = action.payload;
    },
    [fetTodos.rejected]: (state, action) => {
      state.isLoading = false;
      state.error = action.payload;
    },
  },
});

export const {} = todosSlice.actions;
export default todosSlice.reducer;

  • store data 조회 전체 코드 - App.js
import React, { useEffect } from "react";
import { useDispatch } from "react-redux";
import { fetchTodos } from "./redux/modules/todosSlice";

const App = () => {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(fetTodos());
  }, [dispatch]);

  return <div>App</div>;
};

export default App;




출처
리덕스 미들웨어 - 벨로퍼트와 함께하는 모던 리액트
Writing Logic with Thunks - Redux Docs
Redux Essentials, Part 5: Async Logic and Data Fetching - Redux Docs
redux toolkit-thunk를 이용해서 비동기 작업을 처리하는 방법 - 생활코딩

Redux Toolkit은 정말 천덕꾸러기일까? - 화해 블로그

profile
천천히 가더라도 앞으로만 나아가자

0개의 댓글