Redux에서의 비동기 처리와 미들웨어 활용

14.4 react-redux 및 비동기 처리 라이브러리

react-redux는 connect, thunk 등의 함수를 제공합니다. 여기서는 배너 데이터를 가져오는 예제를 통해 비동기 처리 방법을 살펴보겠습니다.

store 설정

비동기 작업은 일반적으로 미들웨어를 사용해야 합니다. configureStore는 이미 redux-thunk를 자동으로 통합하고 있습니다. action에서는 함수를 반환해야 합니다.


import { configureStore } from '@reduxjs/toolkit';
import rootReducer from './reducer/rootReducer';

const store = configureStore({ reducer: rootReducer });
export default store;
action 작성

ACTION_TYPE을 상수로 정의하고, HTTP 요청을 위해 axios를 사용합니다.


import { SET_BANNERS } from './actionTypes';
import axios from 'axios';

export const setBannersAction = (banners) => ({
  type: SET_BANNERS,
  banners
});

export const fetchBanners = () => async (dispatch) => {
  try {
    const response = await axios.get('http://api.example.com/banners');
    dispatch(setBannersAction(response.data));
  } catch (error) {
    console.error('배너 데이터 로드 실패:', error);
  }
};
reducer 구현

전체적인 상태 관리를 위해 여러 reducer를 합칩니다.


import { combineReducers } from 'redux';
import bannerSlice from './slices/bannerSlice';

const rootReducer = combineReducers({
  banner: bannerSlice.reducer
});

export default rootReducer;
개별 reducer: bannerSlice

초기 상태를 설정하고, 다양한 액션 유형에 따라 상태를 업데이트합니다.


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

const initialState = {
  banners: []
};

const bannerSlice = createSlice({
  name: 'banner',
  initialState,
  reducers: {
    setBanners: (state, action) => {
      state.banners = action.payload;
    }
  }
});

export default bannerSlice;
상수 정의

ACTION_TYPE 등을 명확히 하기 위해 상수를 선언합니다.


export const SET_BANNERS = 'SET_BANNERS';
React 애플리케이션에서 store 연결

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from './store';
import { Provider } from 'react-redux';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);
왜 미들웨어가 필요한가?

reducer는 순수 함수여야 하므로 직접 비동기 작업을 수행할 수 없습니다. 따라서 비동기 작업은 미들웨어에서 처리하여 원시 액션을 생성해야 합니다. 이렇게 되면 reducer는 해당 액션을 처리해 상태를 변경하고 UI를 업데이트할 수 있습니다.

Redux Thunk의 단점
  • 비동기 작업 처리 시 많은 보일러플레이트 코드가 필요함.
  • 액션 생성자는 액션 타입뿐 아니라 비동기 논리도 함께 처리해야 함.
Saga 적용하기

Saga는 복잡한 비동기 작업을 더 효율적으로 처리할 수 있도록 도와줍니다.


import { configureStore } from '@reduxjs/toolkit';
import createSagaMiddleware from 'redux-saga';
import bannerSaga from './sagas/bannerSaga';
import rootReducer from './reducer/rootReducer';

const sagaMiddleware = createSagaMiddleware();

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(sagaMiddleware)
});

sagaMiddleware.run(bannerSaga);

export default store;
Saga 내부 로직

Saga는 특정 액션 유형을 감지하고, 이를 기반으로 비동기 작업을 실행합니다.


import { put, takeEvery, call } from 'redux-saga/effects';
import axios from 'axios';
import { FETCH_BANNERS, setBannersAction } from '../actions/bannerActions';

function* fetchBannersSaga() {
  try {
    const response = yield call(axios.get, 'http://api.example.com/banners');
    yield put(setBannersAction(response.data));
  } catch (error) {
    console.error('사가 에러:', error);
  }
}

function* watchFetchBanners() {
  yield takeEvery(FETCH_BANNERS, fetchBannersSaga);
}

export default function* bannerSaga() {
  yield watchFetchBanners();
}

태그: redux redux-saga redux-thunk

5월 20일 10:36에 게시됨