redux-thunk와 redux-saga는 둘 다 미들웨어 라이브러리이다.
redux의 Flux 패턴에서 맨 처음 액션을 dispatch 하게 되면, 리듀서에서 그 해당 액션에 대한 정보를 바탕으로 스토어의 상태값을 바꾸게 되는데, 이때 미들웨어를 사용하면 액션이 스토어에서 상태값을 바꾸기 전에 특정 작업들을 수행할 수 있다.
✔️ Redux Thunk는 비동기 작업을 처리할 때 가장 많이 사용하는 미들웨어로, Redux는 기본적으로 액션객체만을 디스패치할 수 있다. 하지만 Redux Thunk를 활용하면 객체 대신 함수를 생성하는 액션 생성함수를 작성할 수 있게 해준다.(액션 객체가 아닌 함수를 디스패치할 수 있다.) 이러한 동작방식을 활용해서 Redux에서 비동기적인 프로그래밍을 구현할 수 있다.
✔️ 리덕스 스토어와의 상호작용을 위해 getState(),dispatch() 함수를 파라미터로 받아와야하고, 이 함수를 만들어주는 함수를 thunk라고 부른다.
✔️ 따라서 리덕스 스토어의 상태에 접근하거나 또 다른 액션을 디스패치 하는 것이 가능하다.
✔️ 참고로 여기서 전달받은 dispatch() 함수를 호출하면 다음 미들웨어의 dispatch() 함수를 호출하는 것이 아니라 스토어의 dispatch() 함수를 호출하는 것이기 때문에 미들웨어 체인의 맨 처음으로 다시 돌아가게 된다.
✔️ Redux Saga 역시 비동기 작업을 처리하기 위한 미들웨어이다.
✔️ 액션을 모니터링 하고 있다가 특정 액션이 발생했을 때 미리 정해둔 로직에 따라 특정 작업이 이루어지는 '액션에 대한 리스너'이다.
✔️ Sagas라는 순수 함수들로 로직을 처리할 수 있는데, 순수함수로 이루어지다보니, 사이드 이펙트도 적고 테스트 코드를 작성하기에도 용이하다.
✔️ Thunk에 비해 많은 기능을 수행할 수 있다.
✔️ Saga는 제네레이터라는 특수한 형태의 함수로 구현이 된다.
function* generatorFunction () {
console.log('첫 번째 실행')
yield 1;
console.log('두 번째 실행')
yield 2;
console.log('세 번째 실행')
yield 3;
console.log('네 번째 실행')
yield 4;
console.log('다섯 번째 실행')
yield 5;
}
generatorFunction.next();
redux-saga에는 saga의 활용을 돕기 위한 다양한 effects들이 존재한다. 이 effects들은 미들웨어에서 활용할 수 있는 정보들을 담고 있는 자바스크립트 객체의 일종이다. 이 effects들을 활용하여 saga를 보다 효과적으로 사용할 수 있다. 아래는 많이 쓰이는 대표적인 effects들이다.
all
all effect는 제너레이더 함수들이 들어있는 배열을 인자로 받는다. 이렇게 들어온 제너레이터 함수들은 all effect 안에서 병렬적으로 기능을 수행하며, 이 함수들이 모두 resolve 될 때까지 기다린다. promise.all과 비슷한 기능이라고 생각하면 된다.
call
call effect는 함수를 실행시키는 effect이다. 이 effect의 첫 번째 인자에는 함수를 넣고, optional로 나머지 인자에 해당 함수에 넣을 인자를 넣을 수 있다.
fork
fork effect 역시 함수를 실행시키는 effect이다. call과 fork의 차이는 fork의 경우에는 함수를 비동기로 실행하며, call의 경우에는 함수를 동기로 실행한다는 점이다. 따라서 순차적으로 함수가 실행되어야 하는 api 요청 함수 등의 경우에는 call을 사용하며, 그 외의 비동기 로직에는 fork를 사용한다.
put
put effect는 특정 액션을 dispatch하는 effect이다.
takeEvery / takeLatest
takeEvery와 takeLatest는 인자로 들어온 액션에 대해 특정 로직을 실행시켜주는 effect이다. takeEvery와 takeLatest의 차이는 takeEvery의 경우, 인자로 들어오는 모든 액션에 대해 로직을 실행시켜주는 반면, takeLatest는 기존에 실행 중이던 작업이 있을 경우 이를 취소하고, 가장 마지막으로 실행된 작업만 실행한다는 점이다.
Thunk는 Saga에 비해 코드양이 적고 이해하기도 쉽다는 장점이 있다. 그만큼 서비스에도 빠르게 적용이 가능하다. 따라서 서비스의 로직이 작거나 규모가 작은 경우에는 Thunk를 사용하는 것이 더 효율적일 것이다. 하지만, Thunk의 경우 잘 이해하지 못한 상태로 사용했을 때 너무 많은 async 로직을 구현하게 될 수도 있으며, 테스트를 하기 어려운 구조로 되어 있어서 unit test를 자주 하는 환경에서는 적용하기 어렵다는 단점도 있다.
반면에 Saga는 초보자가 사용하기엔 처음에 적어야 할 코드의 양도 많고 제너레이터 함수에 대한 이해가 부족한 경우에 사용하기 힘들기 때문에 러닝 커브도 높은 편이지만, Thunk에 비해서 프로젝트 규모를 키우기에 용이하고, 여러 Saga의 effects들을 활용하면 Thunk에 비해 깔끔한 로직을 구현해낼 수 있다. 또한 Saga는 다양한 기능 활용이 가능하기 때문에 활용도 또한 높다.
프로젝트에 따라 개발 환경은 다 다르기 때문에 Thunk와 Saga의 사용은 그때그때 프로젝트의 규모와 개발환경에 따라 잘 선택해서 사용하는게 좋다. 다만, 간단한 코드를 선호하거나, 로직이 간단한 경우에는 Thunk를 로직이 크고 견고해야 한다면 Saga를 쓰는게 효율적일 것이다.
출처👇