본문 바로가기

React

[React] Redux에서 비동기 작업 처리하는 3가지 방법

Redux 의 Reducers 함수는 다음과 같은 조건이 있습니다.

순수함수여야 하며, 사이트 이펙트에 영향을 받지 않아야 하고, 동기적인 코드여야만 한다는

조건이 바로 그것입니다.

 이는 react 의 useReducer 함수도 같은 조건입니다.

그럼  Redux 사용시, 이런 비동기 코드는 어디에서 작성해야하는 걸까요?

 

3가지 방법이 있습니다.

 

1. 컴포넌트 내에  useEffect() 함수를 사용하여 직접 정의

2. 사용자 정의 action 을 사용( 커스텀 액션 생성자 (Thunk) )

3. createAsyncThunk 사용( redux toolkit 만 가능)

 

1. 비동기 코드 예시

 

1-1. 컴포넌트 내에  useEffect() 함수를 사용하여 직접 정의

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

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('api/data');
        const data = await response.json();
        dispatch(dataActions.setData(data));
      } catch (error) {
        dispatch(dataActions.setError(error.message));
      }
    };

    fetchData();
  }, [dispatch]);
}

 

1-2. 사용자 정의 action 을 사용( 커스텀 액션 생성자 (Thunk) )

 

Redux Toolkit 을 이미 설치 했다면 추가 설치는 필요 없습니다

// dataSlice.js

const dataSlice = createSlice({
  name: 'data',
  initialState: {
  // 생략
  },
  reducers: {
  // 생략
  }
});

export const fetchData = () => {
  return async (dispatch) => { // 설명 2 하단 참조
    try {
      const response = await fetch('api/data');
      const data = await response.json();
      dispatch(dataActions.setData(data));
    } catch (error) {
      dispatch(dataActions.setError(error.message));
    }
  };
};

// Component.js
const Component = () => {
  const dispatch = useDispatch();
  
  useEffect(() => {
    dispatch(fetchData()); // 설명 1 하단 참조
  }, [dispatch]);
}

 

설명 1 ) 기존의 dispatch 는 객체로 된 action을 넘겨줘야 하지만함수를 넣어줄 경우 자동으로 thunk 라이브러리가

작동하면서  설명2) 의 async () 함수의 인자에 자동으로 dispatch 함수를 넣어주어 비동기 코드 전후로 state 값을 변경 요청할 수 있게 된다 (dispatch)

 

그리고 1-1 과는 다르게 component 안에서 직접 코드를 두는 게 아닌 store 파일들의 createSlice 함수 블럭의

밖에서 비동기 코드를 사용하게 된다

 

 

1-3. createAsyncThunk 사용

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

export const fetchData = createAsyncThunk(
  'data/fetchData',
  async () => {
    const response = await fetch('api/data');
    return response.json();
  }
);

const dataSlice = createSlice({
  name: 'data',
  initialState: { data: null, status: 'idle', error: null },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchData.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(fetchData.fulfilled, (state, action) => {
        state.status = 'succeeded';
        state.data = action.payload;
      })
      .addCase(fetchData.rejected, (state, action) => {
        state.status = 'failed';
        state.error = action.error.message;
      });
  },
});

 

 

2. 각 방법의 장단점 

 

2-1 useEffect 방식


장점: 구현이 간단함
단점: 비즈니스 로직이 컴포넌트에 존재

 


2-2 커스텀 액션 생성자


장점: 비즈니스 로직을 리덕스 파일에서 관리
단점: 에러 처리가 복잡할 수 있음

 


2-3 createAsyncThunk


장점:
로딩, 성공, 실패 상태 자동 관리
타입스크립트 지원이 우수
에러 처리가 체계적


단점:
초기 설정이 다소 복잡
학습 곡선이 있음