redux-saga를 사용한 비동기 작업 처리
비동기 작업을 처리하는 라이브러리
리덕스에서 조치 후, 비동기 처리통해 상태 값 변경당신이 원하는 경우 사용
- redux-thunk
- redux-observable (RxJS 패키지 기반)
- redux 사가
: 발전기 기반, 사용하기 쉽고 테스트 코드를 작성하기 쉽습니다.
발전기
발전기는 기능*로 작성
function* f1() {
console.log('f1-1');
yield 10;
console.log('f1-2');
yield 20;
console.log('f1-3');
return 'finished';
}
const gen = f1();
console.log(gen.next());
/*
실행구간
console.log('f1-1');
yield 10;
반환객체
{ value: 10, done: false }
*/
console.log(gen.next());
/*
실행구간
console.log('f1-2');
yield 20;
반환객체
{ value: 20, done: false }
*/
console.log(gen.next());
/*
실행구간
console.log('f1-3');
yield 30;
반환객체
{ value: 'finished', done: true }
*/
다음 기능 (제너레이터 객체 내부의 함수)
발전기의 수율 간격기반으로호출로 나누어
값: 권리 가치 산출 / 완료: 모든 생성기 기능이 완료되었는지 여부
반복자 대 반복 가능
| 반복자 | 반복 가능 |
| 다음 기능 사용 가능 | Symbol.iteraor() 재산 가치로 가지고 |
| 다음 함수: value/done 속성 값의 개체를 반환합니다. | Symbol.iteraor()가 호출되면 반복자를 반환합니다. |
| 작업이 끝나면 done ==true |
제너레이터는 이터레이터이자 이터러블입니다.안돼.
이 때문에 for of 문과 스프레드 연산자를 사용할 수 있습니다.
function* f1() {
yield 10;
yield 20;
yield 30;
}
for (const v of f1()) {
console.log(v);
}
const arr = (...f1());
console.log(arr); // ( 10, 20, 30 )
발전기 예
function* user() {
const userMessageList = ('Hi, I am keeper!', 'Nice to meet you!');
for (const message of userMessageList) {
console.log('User: ', yield message);
}
}
function kepper() {
const gen = user();
const robotMessageList = ('', 'Hi, I am user!');
for (const message of robotMessageList) {
console.log('Keeper: ', gen.next(message).value);
}
}
제너레이터 next에 값을 인자로 전달하면 전달된 인자는 수율의 반환 값
- gen.next(”)=> 로그: 키퍼: 안녕하세요, 키퍼입니다!
- gen.next(‘Hi, I am user!’)=> 로그: User: 안녕하세요, 저는 User입니다!
- 반복하다
Redux 사가 함수: user()
Redux Saga 미들웨어: keepper()
Redux Saga 효과 기능
놓다 : 동작 발생
부르다 : 서버 API 호출
테이크리딩 (<-> 최신)
두 번째 인수 함수가 아직 진행 중입니다.만약에 사이의 작업 무시하다 먼저 들어온 조치가 우선합니다.할 수 있습니다.
import { all, call, put, takeLeading } from 'redux-saga/effects';
export function* fetchData(action) {
yield put(actions.setLoading(true));
yield put(actions.addLike(action.timeline.id, 1));
yield call(callApiLike);
yield put(actions.setLoading(false));
}
export default function* () {
yield all((
takeLeading(type.REQUEST_LIKE, fetchData)
// takeLeading(type.REQUEST_LIKE1, fetchData1)
// takeLeading(type.REQUEST_LIKE2, fetchData2)
// takeLeading(type.REQUEST_LIKE3, fetchData3)
));
}
함수 반환 객체 가져오기
var takeReturn = take(types.REQUEST_LIKE);
var takeReturnLog = {
TAKE: {
pattern: 'timeline/REQUEST_LIKE'
}
}
put 함수 반환 객체
var putReturn = put(actions.setLoading(false));
var putReturnLog = {
PUT: {
channel: null,
action: {
type: 'timeline/SET_LOADING',
isLoading: false
}
}
}
호출 함수 반환 객체
var callReturn = call(callApiLike);
var callReturnLog = {
CALL: {
context: null,
fn: callApiLike,
args: (),
}
}
반환된 객체는 yield를 호출할 때 반환됩니다. saga 미들웨어로 전달
Saga 미들웨어는 부작용이 완료된 후 결과 와 함께 실행 흐름을 생성기(fetchData)로 다시 전달합니다.
redux saga 미들웨어 추가
import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import { createSagaMiddleware } from 'redux-saga';
import { all } from 'redux-saga/effects';
const reducer = combineReducers({
timeline: timelineReducer,
friend: friendReducer,
})
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
reducer,
composeEnhancers(
applyMiddleware(sagaMiddleware)
)
)
function* rootSaga() {
yield all((
timelineSaga(),
friendSaga()
));
}
sagaMiddleware.run(rootSage);
export default store;
- 기존 redux 애플리케이션 코드에서 createSaga미들웨어() 사용하여 생성
- createStore에서, 미들웨어 등록 composeEnhancers 기능을 입력, 적용미들웨어 함수에 미들웨어 객체 넣기주다.(다수의 applyMiddleware 입력 가능)
- all 함수를 통해 모든 saga를 추가한 후 saga 미들웨어를 실행합니다.
여러 작업 처리
LOGIN 및 LOGOUT 작업 처리
function* loginFlow() {
while(true) {
// (로그인)
// 로그인 액션을 기다림
// 로그인 API 호출
// 로그인 정보를 저장
const { id, password } = yield take(types.LOGIN);
const userInfo = yield call(callApiLogin, id, password);
yield put(types.SET_USER_INFO, userInfo);
// (로그아웃)
// 로그아웃 액션을 기다림
// 로그아웃 API 호출
// 로그인 정보를 제거
yield take(types.LOGOUT);
yield call(callApiLogout, id);
yield put(types.SET_USER_INFO, null);
}
}
Redux 사가 예외 처리
try/catch 문을 사용하여 예외 처리
import { all, call, put, takeLeading } from 'redux-saga/effects';
export function* fetchData(action) {
yield put(actions.setLoading(true));
yield put(actions.addLike(action.timeline.id, 1));
// 에러처리
try {
yield call(callApiLike);
} catch (error) {
// 에러객체 저장
// Like 원래상태로 되돌림
yield put(actions.setValue('error', error));
yield put(actions.addLike(action.timeline.id, 1));
}
yield put(actions.setLoading(false));
}
export default function* () {
yield all((
takeLeading(type.REQUEST_LIKE, fetchData)
));
}
디바운스
: 동일한 함수가 연속으로 여러 번 호출될 때 첫 번째 또는 마지막 호출만 실행하는 기능
Reduxa saga 디바운스 기능
일정 시간 내 생성기 기능 여러 번 호출해도 한 번만 실행
REQUEST_LIKE 액션이 발생하면 바로 함수를 호출하지 않고 1초간 기다린다. 더 이상 작업이 발생하지 않으면 fetchData 함수를 실행합니다.
import { all, call, put, takeLeading } from 'redux-saga/effects';
export function* fetchData(action) {
yield put(actions.setLoading(true));
yield put(actions.addLike(action.timeline.id, 1));
try {
yield call(callApiLike);
} catch (error) {
yield put(actions.setValue('error', error));
yield put(actions.addLike(action.timeline.id, 1));
}
yield put(actions.setLoading(false));
}
export default function* () {
yield all((
debounce(1000, type.REQUEST_LIKE, fetchData)
));
}
원천 : https://keeper.44?category=940178
(React.js) React_redux-saga
redux-saga를 이용한 비동기 액션 처리 비동기 액션을 처리하는 라이브러리 Redux redux-thunk redux-observable(RxJS 패키지)에서 액션을 처리한 후 비동기 처리를 통해 상태 값을 변경하고자 할 때 사용
keeper.tistory.com