- redux-saga 목차
| Redux-saga란?
redux-saga
는 리액트/리덕스 애플리케이션의 부수효과(Side-Effect)
라고 합니다.
특정 액션들이 스토어에 보내질 때, 여러 작업들을 함께 실행하기 위한 내부적인 함수를 감싸는 몇몇 helper effect
를 제공하며,function*
문법을 사용합니다.
eX) fetching 이나 브라우저 캐시에 접근하는 순수하지 않은 비동기 동작들을 더 쉽고 좋게 만드는 것을 목접으로 하는 라이브러리입니다.
- Ajax 콜
- 비동기 타이머
- 애니메이션 후 콜백
- 요청 중 취소
- 스로틀링
- 디바운싱
- 페이지 이동
구성
Saga
는 액션을 구독하는 Watcher
와 실제 작업을 수행하는 Worker
의 구성을 따릅니다.
- Watcher
- watcher 함수
- Worker
- exmapleWorker 1
- 2
- ...
Watcher
는 action의 상태를 subscribe
하는 역할을 합니다.Worker
는 exapleWorker1, 2, .. 등과 같이 실제 작업을 수행하는 부분이며
먼저, Saga를 실행하기 위해 redux-saga 미들웨어를 리덕스 스토어에 연결하는 방법을 알아봅시다.
모듈 설치
yarn add redux-saga
Saga
는 Object
들을 redux-saga 미들웨어에 yield
하는 제너레이터
함수로 구현되었습니다.
yield된 Object 들은 미들웨어에 의해 해석되는 명령의 한 종류입니다.
put
: Saga에선는 Saga-effect
라고 부르는 예 중 하나입니다. 이펙트는 미들웨어에 의해 수행되는 명령을 담고 있는 javascript 객체입니다.put
은 redux store에 dispatch 하는 역할 을 의미합니다.
(= Redux의 dispatch와 동일합니다.)
takeEvery
: 가장 흔히 사용되는 함수입니다. takeEvery는 동시에 시작되는 여러 개의 fecthData instance들을 허용합니다.
액션이 dispatch될 때 마다 특정 함수를 실행합니다.
all
: Saga가 여러개 묶어서 사용하고 싶으면 allEffect를 사용해서 아래와 같이 만들어 줄 수 있습니다.
import {all} from 'redux-saga/effects';
//all 함수를 통해 Saga들을 하나로 묶어줄 수 있습니다.
export default funtion* rootSaga(){
yield all([
example1()
,example2()
])
}
그 후 아래와 같이 sagaMiddleware.run()에 넣어주면 됩니다.
sagaMiddleware.run(rootSaga)
| Saga-Effect
Saga는 이러한 부수효과를 처리하는 이펙트들을 지원합니다.
앞의 설명에서는 put
과 takeEvery
가 있습니다.
여기서 중요한 점은 모든 effect 들은 반드시 yield
와 함께 사용 해야 합니다.
take
take
는 특정 액션을 감시하는 용도로 사용합니다.
다음 코드는 REQUEST_ORDER 액션이 디스패치될 때까지 기다린 후 Api.requestOrder 를 호출하는 코드입니다.
function* watchOrdeRequest(){
const action = yield take('REQUEST_ORDER');
const result = yield call(Api.requestOrder,action.orderId);
// ... process ...
}
블럭된다는 성질을 이용해서 다음과 같이 매번 action에 대해 반응하는 saga를 만들 수 있습니다.
function* watchOrderRequest(){
//무한루프
while(true){
//하지만 해당 라인에서 블럭된다.
const action = yield take("REQUEST_ORDER");
const result = yield call ("APi.requestOrder", action.orderId);
//process ...
}
}
위와 같은 saga 를 만들 일이 많아서 공식적으로 이런 동작의 helper
인 takeEvery
, takeLatest
, takeLeading
등을 제공하고 있습니다.
put
put effect는 단순히 redux의 dispatch 함수와 동일합니다.
해당 effect는 블럭이 되지 않기에 조심해야합니다.
function* watchOrderRequest(){
// 무한 루프
while(true){
const action = yield take("REQUEST_ORDER");
const result = yield call(Api.requestOrder, action.orderId);
//결과를 스토어에 디스패치(put)한다.
yield put({ type : "RESPONSE_ORDER", result });
}
}
fork
새로운 하위 saga 작업를 생성하는 effect입니다.
fork
는 블럭되지 않기에 (non-block
) 호출 시점에 호출자는 부모 task 가 되고 fork
된 saga
는 자식 task 가 됩니다.
부모 task가 취소되면, 자식 task도 취소됩니다.
명시적으로 특정 자식 task만 취소시킬 수 있습니다.
function* parentTask(){
const task1 = yield fork(자식task1);
const task2 = yield fork(자식task2);
// do something ...
//아직 동작중이면 취소시킨다.
if(task2 && task.isRunning() ) {
task2.cancel();
}
}
call
call
은 block 되는 fork 라고 보면 됩니다.인자
로 함수
나 saga task
를 받을 수 있습니다.
두 번째부터는 실행 될 함수나 saga 인자로 들어갑니다.
보통 Promise
등의 실행 (보통 Ajax Call)에 사용됩니다.Promise
가 resolve
될 때까지 블럭
됩니다.
//resolve될 때 까지 기다립니다.
const result = call("Api.requestOrder",action.orderId);
select
redux
의 state
에서 특정 상태
를 가져올 때 사용하는 블럭 effect 입니다.
redux-thunk 의 getState
와 비슷하지만, 인자로 selector
를 줄 수 있습니다.
const activeUserSelector = state =>{
return state.user.activeUser;
};
const getUSerData = userId => ajax(`/user/data/${userId}`);
function* parentTask(){
const activeUser = yield select(activeUserSelector);
const activeUserData = yield call(getUserData, activeUser.userId);
}
'React' 카테고리의 다른 글
리덕스 reselect 사용하기 (0) | 2021.02.22 |
---|---|
react-redux의 shallowEqual 사용하기 (0) | 2021.02.22 |
CORS와 Webpack DevSercer Proxy (0) | 2021.02.18 |
redux-thunk란? (0) | 2021.02.18 |
리덕스 미들웨어 (0) | 2021.02.17 |