[react] Redux Toolkit 사용(2) createAsyncThunk

Subin Ryu·2024년 10월 30일
post-thumbnail

Redux Toolkit 사용(2) createAsyncThunk

  1. 목적
  2. 사용방법

목적

  • 비동기 작업의 상태를 자동으로 관리할 수 있도록 하고, extraReducers를 통해 상태 변화(pending, fulfilled, rejected)를 쉽게 반영할 수 있게 함

사용 방법

  • 기존 action.js 파일에 있는 내용을 createAsyncThunk에 옮겨서 reducer.js 파일에 통합
  1. reducer.js 파일 변경 (action 파일을 별도로 두지 않고 통합시킴)
// reateAsyncThunk 불러오기
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

let initialState = {
  productList: [],
  productDetailList: null,
  isLoading: false,
  error: null,
};

// 2개의 파라미터 action 타입(이름)의 string, 하고 싶은 일 콜백함수(promise 리턴)
export const fetchProducts = createAsyncThunk(
  'product/fetchAll',
  // 콜백함수는 2개의 매개변수 받음(arg, thunkAPI)
  // arg: api 호출 전 넘겨야하는 single value
  async (searchQuery, thunkApi) => {
    try {
      let url = `https://my-json-server.typicode.com/ryugotthis/shoppingmall-toolkit/products?q=${searchQuery}`;
      let response = await fetch(url);
      // promise 리턴
      return await response.json();
    } catch (error) {
      // fetchProducts.rejected로 error 메시지 action.payload로 보냄
      thunkApi.rejectWithValue(error.message);
    }
  }
);

const productSlice = createSlice({
  name: 'product',
  initialState,
  reducers: {
    // 리덕스에서 직접적 호출되는 경우
    //  getSingleProduct는 thunk(미들웨어)사용하는 action.js에 action이 별도로 정의되어서 dispatch로 넘겨줌
    getSingleProduct(state, action) {
      state.productDetailList = action.payload;
    },
  },
  //외부 라이브러리에 의해서 호출이 되는 경우
  extraReducers: (builder) => {
    builder
      .addCase(fetchProducts.pending, (state) => {
        state.isLoading = true;
      })
      .addCase(fetchProducts.fulfilled, (state, action) => {
        // 성공이 된 케이스니까 isLoading 먼저 false로 만들어줌
        state.isLoading = false;
        state.productList = action.payload;
      })
      .addCase(fetchProducts.rejected, (state, action) => {
        state.isLoading = false;
        //에러시 try catch문에서 받은 error.message를 action으로 받을수 있음
        state.error = action.payload;
      });
  },
});

export const productActions = productSlice.actions;

// reducer에 모든 reducers 있음
export default productSlice.reducer;

action.js

import { productActions } from '../reducer/productReducer';

function getProductDetail(id) {
  return async (dispatch, getState) => {
    let url = ` https://my-json-server.typicode.com/ryugotthis/shoppingmall-toolkit/products/${id}`;
    let response = await fetch(url);
    let data = await response.json();
    console.log('여기여기여기여기여기', data);
    dispatch(productActions.getSingleProduct(data));
  };
}

export const productAction = { getProductDetail };
profile
개발블로그입니다.

0개의 댓글