import { all, fork, takeLatest, call, put, take, delay } from 'redux-saga/effects';
import { HELLO_SAGA } from '../reducers/user';
function* helloSaga() {
console.log('before saga');
yield take(HELLO_SAGA); // HELLO_SAGA 액션이 들어오면 함수 재진행
console.log('hello saga'); // HELLO_SAGA 액션 이후 -> 'hello saga'
}
export default function* userSaga() {
yield all([fork(watchLogin), helloSaga()]);
}
위의 예제의 helloSaga
제너레이터는 HELLO_SAGA 액션이 한 번 들어오면 함수가 끝이난다.
HELLO_SAGA 액션이 들어올 때 마다 특정 동작을 하게 하기 위해서는 while
문을 통한 제너레이터의 무한반복문을 활용할 수 있다.
function* helloSaga() {
console.log('before saga');
while (true) {
yield take(HELLO_SAGA);
console.log('hello saga');
}
}
dispatch(HELLO_SAGA) // -> 'hello saga'
dispatch(HELLO_SAGA) // -> 'hello saga'
dispatch(HELLO_SAGA) // -> 'hello saga'
.
.
.
이벤트리스너를 동기적으로 표현했다고 생각하면 이해하기 쉽다.
LOG_IN 액션 이후 2초 뒤 LOG_IN_SUCCESS 액션 dispatch
import { all, put, take, delay } from 'redux-saga/effects';
import { LOG_IN, LOG_IN_SUCCESS } from '../reducers/user';
function* watchLogin() {
while (true) {
yield take(LOG_IN); // LOG_IN 이 dispatch 되면, take로 인해 함수 다음 단계 실행
yield delay(2000); // delay 이펙트: 일정 시간 후 다음 함수 단계 실행.
yield put({ // 그렇기 때문에 put 실행됨
type: LOG_IN_SUCCESS,
});
}
}
export default function* userSaga() {
yield all([watchLogin(), watchSignUp()]);
}
put
은 dispatch로 생각하면 된다.
put
은 dispatch로 생각하면 된다.
takeEvery
는 모든 액션에 대하여 동작한다.
일단은 takeEvery
를 사용하지 않고, take
만 사용하여 예제를 작성해보자.
import { take } from 'react-saga/effects';
function* watchHello() {
while (true) {
yield take(HELLO_SAGA);
console.log(1);
console.log(2);
console.log(3);
console.log(4);
}
}
위의 예제는 redux-saga의 이펙트인 takeEvery
를 사용하여 다음과 같이 작성할 수 있다.
import { take, takeEvery } from 'react-saga/effects';
function* watchHello() {
yield takeEvery(HELLO_SAGA, function*() {
// 어떤 동작을 하는 지 코드 작성
console.log(1);
console.log(2);
console.log(3);
console.log(4);
});
}
takeEvery
또는 takeLatest
는 take
와는 달리 특정 동작을 명확하게 지정하여 코드를 작성할 수 있기 때문에 코드 가독성 측면에서 더 좋다.
takeEvery
가 같은 종류의 액션이라도 모든 액션에 대하여 주어진 동작을 실행하는 반면에,
takeLatest
는 같은 종류의 액션이 여러 번 요청된다면 가장 마지막 액션에 대해서만 동작을 실행한다. 즉 이전 액션 요청이 끝나지 않았음에도 불구하고 같은 종류의 액션이 여러 번 요청된다면 이전 요청을 취소한다. 웹페이지에서 특정 버튼을 여러 번 클릭하는 경우에 사용한다고 생각하면 된다.
import { take, takeLatest } from 'react-saga/effects';
function* watchHello() {
yield takeLatest(HELLO_SAGA, function*() {
console.log(1);
console.log(2);
console.log(3);
console.log(4);
});
}
call(fn, ...args)
Creates an Effect description that instructs the middleware to call the function
fn
withargs
as arguments.
- fn: Function - A Generator function, or normal function which either returns a Promise as result, or any other value.
- args: Array - An array of values to be passed as arguments to fn
Redux-Saga API 레퍼런스 · GitBook
fork
와 call
모두 함수를 실행시켜주는 이펙트이다. 두 가지는 다음과 같은 차이가 있다.
fork
는 비동기 실행을 한다.
call
은 동기 실행을 한다. 따라서 순서대로 함수를 실행해야하는 API 요청 같은 곳에 쓰인다.
import { all, fork, call, put } from 'redux-saga/effects';
import { LOG_IN, LOG_IN_SUCCESS, LOG_IN_FAILURE } from '../reducers/user';
function loginAPI() {
// 서버에 요청을 보내는 부분
}
function* login() {
try {
yield fork(logger); // fork는 비동기 요청. logger는 내 기록을 로깅하는 함수. 10초 걸림
yield call(loginAPI); // call은 동기 요청
yield put({
//put은 dispatch와 동일
type: LOG_IN_SUCCESS,
});
} catch (e) {
console.error(e); // loginAPI 실패
yield put({
type: LOG_IN_FAILURE,
});
}
}
export default function* userSaga() {
yield all([fork(watchLogin)]); // yield all([watchLogin()]) 과 같음
}