개발/React

[리액트를 다루는 기술] 리덕스 미들웨어를 통한 비동기 작업 관리

hayo 2023. 4. 8. 01:22
리액트 웹 애플리케이션에서 API가 서버를 연동할 때는 API 요청에 대한 상태도 잘 관리해야 하기 때문에, '리덕스'가 주로 사용된다.
그 중에서도 효율적이고 편하게 비동기 작업에 대한 상태 관리를 하고 싶다면 '미들웨어(Middleware)'를 사용하면 된다.

 

1. 미들웨어란?

  • 액션과 리듀서 사이의 중간자라고 볼 수 있다.
    • 액션을 디스패치했을 때, 리듀서에서 이를 처리하기 전에 지정된 작업을 실행한다.
    • 미들웨어는 전달받은 액션을 콘솔에 기록하거나, 전달받은 액션 정보를 기반으로 액션을 취소하거나, 다른 종류의 액션을 추가로 디스패치하는 등 여러가지 작업을 할 수 있다.
  • 함수를 반환하는 함수이다.
  • middleware의 구성
    • store - 리덕스 스토어 인스턴스
    • next - 파라미터 함수 형태.
               - store.dispatch와 비슷한 역할을 하지만,
                  next(action)이 호출되었을 때 그다음 처리해야 할 미들웨어가 없다면 리듀서에서 액션을 넘겨준다.
    • action - 디스패치된 액션

 

  • 참고!
    • 미들웨어 내부에서 store.dispatch를 사용하면 첫 번째 미들웨어부터 다시 처리한다.
    • 미들웨어에서 next를 사용하지 않으면 액션이 리듀서에 전달되지 않는다! === 액션이 무시된다!
// loggerMiddleware.js

const loggerMiddleware = store => next => action =< {
  // 미들웨어 기본 구조
};

export default loggerMiddleware;


// 위의 화살표 함수로 쓰인 구조를 function으로 풀어서 쓰면, 하기와 같다.
const loggerMiddleware = function loggerMiddleware(store) {
  return function(next) {
    return function(action) {
      // 미들웨어 기본 구조
    };
  };
};

 

2. 비동기 작업을 처리하는 미들웨어 사용

redux-thunk

  • 비동기 작업을 처리할 때 가장 많이 사용되는 미들웨어 라이브러리
  • 객체가 아닌, 함수 형태의 액션을 디스패치할 수 있게 해줌
  • Thunk는 특정 작업을 나중에 할 수 있도록 미루기 위해 함수 형태로 감싼 것을 의미한다.
  • 비록 처음 쓸 때는 작성해야 하는 코드가 많아서 불편할 수 있지만, 유용한 리듀서를 만들어서 상태를 관리한다면 클린 코드로 기능 구현이 가능하다.
const sampleThunk = () => (dispatch, getState) => {
  // 현재 상태를 참조할 수 있고,
  // 새 액션을 디스패치할 수도 있음
}

redux-saga

  • redux-thunk 다음으로 가장 많이 사용되는 비동기 작업 관련 미들웨어 라이브러리
  • 특정 액션이 디스패치되었을 때, 정해진 로직에 따라 다른 액션을 디스패치시키는 규칙을 작성하여 비동기 작업을 처리할 수 있게 해줌
  • redux-thunk를 사용하는 상황보다 좀 더 까다로운 상황에서 유용하다.
    • 기존 요청을 취소 처리해야 할 때(불필요한 중복 요청 방지)
    • 특정 액션이 발생했을 때, 다른 액션을 발생시키거나, API 요청 등 리덕스와 관계없는 코드를 실행할 때
    • 웹소켓을 사용할 때
    • API 요청 실패 시 재요청해야 할 때
  • ES6의 제너레이터(generator) 함수 문법을 사용한다.
    • 제너레이터 함수를 사용하면 하나의 함수에서 여러 개의 값을 순차적으로 반환할 수 있다.
    • 함수의 흐름을 도중에 멈춰 놓았다가 다시 이어서 진행시킬 수도 있다.
    • 제너레이터 함수를 만들 때는 function* 키워드를 사용해야 한다.
    • 제너레이터가 처음 만들어지면 함수의 흐름은 멈춰 있는 상태이다.
더보기
function* generatorFunction() {
  console.log('안녕');
  yield 1;
  console.log('제너레이터');
  yield 2;
  console.log('함수에요!');
  yield 3;
  return 4
}


// 작성된 함수로 '제너레이터'를 생성
const generator = generatorFunction();

generator.next();
// 안녕
// {value: 1, done: false}
generator.next();
// 제너레이터
// {value: 2, done: false}
generator.next();
// 함수에요!
// {value: 3, done: false}
generator.next();
// {value: 4, done: true}
generator.next();
// {value: undefined, done: true}
  • redux-saga는 제너레이터 함수 문법을 기반으로 비동기 작업을 관리해 준다.
  • 개발자가 디스패치하는 액션을 모니터링해서 그에 따라 필요한 작업을 따로 수행할 수 있는 미들웨어이다.

 

3. 정리

  • redux-thunk - 일반 함수로 이루어져 있어 간단명료하다.
  • redux-saga -  진입 장벽이 조금 있을 수 있으나, 복잡한 상황에서 더욱 효율적으로 작업을 관리할 수 있다.

redux-promise-middleware, redux-pender, redux-observable 등 여러가지 미들웨어가 있지만, 결국 미들웨어를 사용하는 이유는 비동기 작업을 처리할 때 좀 더 편하게 처리하기 위함이다. 따라서, 오히려 미들웨어를 사용하는 것이 불편하다면 굳이 사용하지 않는 편이 좋을 수도 있다.

 


참고자료

  • 리액트를 다루는 기술 [김민준 저]