redux-thunk와 redux-saga는 redux-middleware로 비동기 작업을 진행할 때 많이 사용된다. 그렇다면 비동기 작업에 사용되는 이 두 미들웨어의 각각의 특징과 이점은 무엇이며 어느 경우에 어떤 미들웨어를 사용하는게 좋을까?
const thunkName = parameters => (dispatch, getState) => {
// 당신의 어플리케이션 로직을 여기에 적으세요
dispatch(actionCreator());
};
리덕스는 기본적으로 액션 "개체"를 디스패치한다.
그러나 redux-thunk를 사용하면 함수를 디스패치 할 수 있다.
redux-thunk의 이런 특징을 활용하면 action의 다른 property를 설정할 필요없이 paramter를 받아와서 작업을 할 수 있다. 그렇기 때문에 비동기 작업 요청, 성공,실패의 다양한 action 작업을 진행하고 액션의 결과물과 paramter의 type 이 다를 경우 thunk를 활용하는 것이 매우 유용하다.
const loading ="loading";
const success ="success";
const error ="error";
export type DataState = typeof none| typeof loading| typeof success|typeof error;
export type WeatherState ={
state:DataState,
error:Error|null,
nowWeather:NowWeather |null,
threeDay:DailyWeather[]|null,
weekly:Day[]|null,
nation:Area[]|null,
sunRiseAndSet :SunRiseAndSet |null
};
const getWeatherAsync =createAsyncAction(
GET_WEATHER_REQUEST,
GET_WEATHER_SUCCESS,
GET_WEATHER_FAILURE
)<undefined, WeatherState, Error>();
export const getWeatherThunk =(position:PositionState):ThunkAction<void,WeatherState, unknown,WeatherAction>=>async(dispatch)=>{
const {loading,success,failure}=getWeatherAsync;
const {longitude, latitude}=position;
dispatch(loading());
try{
const data = await getWeatherData(longitude,latitude);
dispatch(success(data));
}catch(error){
const e = New Error(`${error}`);
dispatch(failure(e));
}
....
};
const App =()=>{
....
const getData=()=>{
navigator.geolocation.getCurrentPosition(
(pos:GeolocationPosition)=>{
//.... 현재 위치 가져오는...
const position:PositionState ={...};
getWeatherThunk(position);
....
}, (error)=>{
//Error
};
};
};
만약 이러한 상황에서 redux-saga를 사용해야 한다면 다음 두가지의 경우의 추가적을 작업이 필요하다.
기존의 action 생성함수를 유지한 경우
GET_WEATHER_REQUEST의 action.payload type을 WeatherState으로 변경
WeatherState에 현재의 위치를 표현하는 property들을 추가
action.payload 에서 logitude와 latitude의 값을 가져옮
새로운 action 생성함수를 만들 경우
redux-saga를 위한 별도의 action 생성함수 추가
action에 현재 위치에 대한 날씨 데이터를 가져오는 함수에서 필요로하는 paramter 값을 action의 property(ex: meta)에 추가 & action.meta 에서 logitude와 latitude의 값을 가져옮
redux-saga는 헬퍼함수를 활용해, 스토어에서 지정된 특정 액션이 발생했을 때 generator함수에서 지정된 작업들(ex:다른 액션을 디스패치 한다거나, 데이터를 가공하는)이 진행한다.
redux-saga가 가지는 차별점은 무엇일까? 바로 redux-saga가 제공하는 다양한 effect들(이하 이팩트)이다.
🖱️redux-saga Effect creator 보러가기
이펙트는 사가의 미들웨어가 실행할 명령을 포함하고 있는 평범한 자바스크립트 객체입니다.
또한 yeild를 통해 모든 이펙트들을 통합, 관리할 수 있다.
이펙트는 사가의 미들웨어가 실행할 명령을 포함하고 있는 평범한 자바스크립트 객체입니다.
다양한 이팩트들과 이를 통합, 관리할 수 있는 yeild를 통해 redux-saga는 다음과 같은 장점을 가지고 있다.
이는 액션이 디스패치 되어서 리듀서에서 해당 액션의 결과에 따라 상태를 업데이터하기 전에 추가적인 작업을 할 수 있는 미들웨어로서의 이점에 부합하는 장점이기도 하다.
action의 property를 추가/수정하지 않아도 paramter를 받아와 사용할 수 있다.
thunk는 dispatch에서 액션 생성함수를 대신해 사용된다. 원래 액션 생성함수는 action type과 그 결과값(payload)를 담은 객체를 반환하는데 thunk함수는 어떤 경우에는 객체를 반환하고 어떤 경우에는 함수를 반환한다.
또한 thunk 함수는 콜백지옥에 빠질 수 있고, 비동기 작업 테스트가 어렵다.
다양한 이팩트들을 활용하여 다양한 작업을 할 수 있으며 비동기 작업의 흐름과 테스트를 보다 쉽게 할 수 있다.
흔히 사용되지 않는 generator 문법을 배워야한다.
특정한 객체를 saga함수 밖에서 받아와야할 경우, paramter로 받아 올 수 없으며 action의 결과값이나 property로 받아와야해서 이에 대한 추가적인 작업이 필요하다.
비동기 작업이 단순하게 데이터를 받아오는 작업이라면 redux-thunk를 사용하는 것을 추천하고 싶다. 코드가 보다 단순하며 데이터를 받아오는 속도가 근소하지만 redux-saga보다는 빨랐다. redux-saga는 보다 다양한 작업을 하고 싶고, 보다 복잡한 비동기 작업이 필요할 때 사용하는 것이 좋다고 느꼈다.
🖱️ redux-middleware 를 공부하며 정리한 github 저장소 보러가기
🖱️redux-thunk, redux-saga를 이용한 날씨 웹 사이트 프로젝트 보러가기