redux-saga는 리덕스 앱에서 '사이드 이펙트'를 특별한 방법으로 처리하기 위한 Redux 미들웨어입니다. 여기서 '사이드 이펙트'라 함은 우리가 작성한 코드가 외부 세계와 영향을 주고 받는 일을 일컫습니다. 예를 들어, 어떤 함수가 그 내부에서 비동기적으로 API를 호출한다거나 브라우저 캐시에 접근하고 있다면, 이 함수는 사이드 이펙트를 갖는 것으로 간주됩니다. 그런데 도대체 이런 '사이드 이펙트'가 뭐가 문제길래, 사람들은 리덕스 앱에서 redux-saga와 같은 미들웨어를 사용하여 사이드 이펙트를 별도로 처리해주려 하는 걸까요?

어떤 함수가 사이드 이펙트를 갖고 있다, 즉 외부 세계와 영향을 주고 받는다는 것은 결국 함수의 내부적인 처리 결과가 외부 세계의 상태에 따라 달라질 것이므로 동일한 입력값에 대해 일관된 결과를 보장하지 못한다(순수하지 못하다)는 것을 의미합니다. 이처럼 순수하지 못한 작업은 우리가 작성한 코드를 예측 불가능하게 만들고 이로 인해 해당 코드를 테스트하는 일 역시 어려워지게 됩니다. 리덕스는 이러한 문제가 발생하는 것을 사전에 방지하고자, 애초부터 스토어의 상태 변화를 기술하는 리듀서는 순수 함수로 작성되어야 한다는 핵심 원칙을 세웠습니다.


Redux를 비동기 작업 안에서 사용하기 위해 Thunk 라이브러리를 사용할 수 있다.

예를 들어, 사용자에게 로딩 인디케이터(Loading Indicator)를 보여준다는 것은 요청을 시작할 때 상태를 변경(액션을 dispatch)하고 그 결과에 따라 로딩 인디케이터가 보여지는 새로운 화면을 그려준다는 것이고, 요청이 완료되면 앞선 것과 마찬가지로 로딩 인디케이터를 다시 숨기기 위해 상태를 변경(액션을 dispatch)해야하며, 에러가 발생했다면 그에 따른 액션을 dispatch해야 하는 상황이 존재한다.

이렇듯 우리가 비동기 API를 호출할 때 매우 중요한 순간이 두 번 있다. 호출을 시작할 때와, 응답을 받았을 때(아니면 타임아웃)이다. 두 순간 모두 애플리케이션에서 상태 변화를 요구하는데, 이를 위해서는 리듀서가 동기적으로 처리할 수 있는 일반 액션을 보내야 한다. 보통 어떤 API 요청이건간에 우리는 최소 3가지 다른 액션을 보내야 할 것이다.

리듀서에게 요청이 시작되었음을 알리는 액션.

리듀서는 이 액션을 처리하기 위해 상태의 isFetching 표지를 바꾸는 것 같은 일을 할 것이다. 이를 통해 UI가 스피너를 표시해야 한다는걸 알 수 있다.

리듀서에게 요청이 성공적으로 완료되었다고 알리는 액션.

리듀서는 새 데이터를 상태에 합치고 isFetching을 되돌려서 이 액션을 처리할 것이다. UI는 스피너를 숨기고 가져온 데이터를 표시한다.

리듀서에게 요청이 실패했음을 알리는 액션.

리듀서는 isFetching을 되돌려서 이 액션을 처리한다. 리듀서는 에러 메시지를 UI에 표시하기 위해 상태에 저장할 수도 있다.

그렇다면, 비동기 작업을 시작할 때와 끝나는 시점을 어떻게 확인하고 그 시점에 알맞게 dispatch할 것인지를 생각해볼 필요가 있다. 동기식 Action Creator라면 단순히 어떤 작업을 할 지를 알려주는 객체를 리턴하면 끝이지만 비동기식 Action Creator는 이와 같은 방식으로는 문제를 해결할 수 없다. 이 문제를 해결하기 위해 비동기식 Action Creator는 함수를 반환하도록 정의하는데, 이 함수는 내부적으로 dispatch를 여러 번 실행한다. 이와 같이 dispatch를 여러 번 수행할 작업을 간단하게 함수로 정의한 후 dispatch하는 것도 가능한데, 이렇게 비동기식 Action Creator에 의해 반환되는 함수를 Thunk라고 한다.