관리 메뉴

Life goes slowly...

🎯 React Saga 완벽 정리: 복잡한 비동기 로직을 간결하게! 본문

프로그래밍/React.js

🎯 React Saga 완벽 정리: 복잡한 비동기 로직을 간결하게!

빨강소 2025. 5. 29. 21:04
728x90
반응형

 

Redux를 사용할 때, 비동기 작업(API 호출, 웹소켓 등)을 깔끔하게 처리하고 싶으신가요?
React Saga는 바로 그런 고민을 해결해주는 미들웨어 라이브러리입니다.

React Saga는 복잡한 비동기 흐름을 선언적으로 표현하고, 유지보수성과 테스트 용이성을 높여주는 강력한 도구입니다.


🔍 사이드 이펙트란?

**사이드 이펙트(side effects)**란 애플리케이션의 주 흐름 외부에서 발생하는 작업을 말합니다.

  • API 호출
  • 브라우저 캐시 접근
  • 웹소켓 통신
    등이 이에 해당되며, 이런 작업은 Redux의 순수한 액션/리듀서 구조에서는 직접 다루기 어렵습니다.

🧠 React Saga란?

React Saga는 Redux 애플리케이션에서 사이드 이펙트를 관리하기 위한 미들웨어입니다.
**ES6 제너레이터(Generator)**를 활용하여 비동기 흐름을 마치 동기처럼 작성할 수 있게 해줍니다.

✅ React Saga의 장점

  • 복잡한 비동기 흐름 처리
    여러 API 호출, 조건 분기, 병렬 실행 등 복잡한 로직을 깔끔하게 관리
  • 테스트 용이성
    제너레이터 함수 + 이펙트 객체로 로직을 테스트하기 쉬움
  • 관심사 분리
    비동기 로직을 컴포넌트나 액션 생성자에서 분리
  • 선언적 프로그래밍
    yield를 통해 코드 의도가 명확하게 드러남

 

⚙️ 주요 개념

1. 📦 사가(Saga)

비동기 작업을 처리하는 제너레이터 함수입니다.

  • 특정 액션을 감시하고 → 해당 작업 수행
  • function* 문법 사용

2. ⚡ 이펙트(Effects)

사가가 미들웨어에게 "무엇을 할지" 명령하는 순수 객체입니다.

주요 이펙트 함수들 (from redux-saga/effects):

이펙트 함수설명
put(action) 액션을 디스패치
call(fn, ...args) 함수를 호출하고 Promise 완료를 기다림
take(pattern) 특정 액션이 발생할 때까지 대기
takeEvery(pattern, saga) 액션마다 사가 실행 (병렬 처리)
takeLatest(pattern, saga) 가장 마지막 액션만 처리 (이전 사가는 취소)
select(selector) Redux 스토어 상태 접근
fork(fn) 비동기 작업을 병렬로 백그라운드 실행
all([...effects]) 여러 이펙트를 병렬 실행

3. 와처 사가 & 워커 사가

  • 와처 사가 (Watcher Saga)
    takeEvery, takeLatest 등을 통해 액션 감시
  • 워커 사가 (Worker Saga)
    실제 비동기 작업을 수행하고, 결과 액션 디스패치

🚀 흐름 예시: 사용자 정보 가져오기

[1] 컴포넌트에서 action dispatch (FETCH_USER_REQUEST)
      ↓
[2] 와처 saga가 감지 (takeLatest 사용)
      ↓
[3] 워커 saga 실행 → API 호출 (call)
      ↓
[4] 성공 시 FETCH_USER_SUCCESS, 실패 시 FETCH_USER_FAILURE 디스패치 (put)
      ↓
[5] Reducer가 상태 업데이트
      ↓
[6] 컴포넌트가 변경된 상태를 반영해 리렌더링

✅ 언제 React Saga를 사용할까?

  • 복잡한 비동기 로직, 동시성 제어가 필요할 때
  • API 호출, 소켓 관리 등 다양한 사이드 이펙트를 체계적으로 관리하고 싶을 때
  • 비동기 로직의 테스트가 중요한 프로젝트일 때
  • 컴포넌트와 로직을 명확히 분리해 코드 유지보수성을 높이고 싶을 때

⚠️ 단순한 비동기 처리라면 redux-thunk도 충분합니다. 하지만 프로젝트가 커질수록 React Saga의 장점이 빛을 발합니다.

 


🛠️ 사용 방법

1. 스토어에 미들웨어 적용

// store.js
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './reducers';
import rootSaga from './sagas';

const sagaMiddleware = createSagaMiddleware();

const store = createStore(
  rootReducer,
  applyMiddleware(sagaMiddleware)
);

sagaMiddleware.run(rootSaga);

2. 루트 사가 정의

// sagas/index.js
import { all } from 'redux-saga/effects';
import { watchFetchUserRequest } from './userSagas';

export default function* rootSaga() {
  yield all([
    watchFetchUserRequest(),
    // 다른 와처 사가 추가 가능
  ]);
}
728x90
반응형
Comments