Upload
daniel-franz
View
136
Download
3
Embed Size (px)
Citation preview
A long, long time ago...
● We were using redux-thunk
● We were chaining actions in actions
● We were providing callbacks to actions
● We were afraid of writing tests
redux-thunkfunction someAction() { return (dispatch) => { dispatch(someActionPending()); someAsyncFunction() .then((result) => { dispatch(someActionSuccess(result)); dispatch(followUpAction()); }) .error((error) => dispatch(someActionError(error)); }}
redux-thunkfunction someAction() { return (dispatch) => { dispatch(someActionPending()); someAsyncFunction() .then((result) => { dispatch(someActionSuccess(result)); dispatch(followUpAction()); }) .error((error) => dispatch(someActionError(error)); }}
redux-thunkfunction someAction() { return (dispatch) => { dispatch(someActionPending()); someAsyncFunction() .then((result) => { dispatch(someActionSuccess(result)); dispatch(followUpAction()); }) .error((error) => dispatch(someActionError(error)); }}
redux-thunkfunction someAction() { return (dispatch) => { dispatch(someActionPending()); someAsyncFunction() .then((result) => { dispatch(someActionSuccess(result)); dispatch(followUpAction()); }) .error((error) => dispatch(someActionError(error)); }}
redux-thunkfunction someAction() { return (dispatch) => { dispatch(someActionPending()); someAsyncFunction() .then((result) => { dispatch(someActionSuccess(result)); dispatch(followUpAction()); }) .error((error) => dispatch(someActionError(error)); }}
redux-thunkfunction someAction() { return (dispatch) => { dispatch(someActionPending()); someAsyncFunction() .then((result) => { dispatch(someActionSuccess(result)); dispatch(followUpAction()); }) .error((error) => dispatch(someActionError(error)); }}
redux-thunkfunction someAction(followUpAction) { return (dispatch) => { dispatch(someActionPending()); asyncFunction() .then((result) => { dispatch(someActionSuccess(result)); dispatch(followUpAction(result)); }) .error((error) => dispatch(someActionError(error)); }}
CALLBACK HELL
Advantages of Redux-Saga
Pure actions
Power of middleware with concise syntax
Readable and testable workflows
Side effects encapsulated in saga
Return from callback hell
Refactored to Redux-Sagafunction* someSaga() { yield put(someActionPending()); try { const result = yield call(someAsyncFunction); yield put(someActionSuccess(result)); yield* followUpSaga(); } catch (error) { yield put(someActionError(error)); }}
function* watchSomeSaga() { yield takeEvery(TYPES.SOME_ACTION, someSaga);}
Refactored to Redux-Sagafunction* someSaga() { yield put(someActionPending()); try { const result = yield call(someAsyncFunction); yield put(someActionSuccess(result)); yield* followUpSaga(); } catch (error) { yield put(someActionError(error)); }}
function* watchSomeSaga() { yield takeEvery(TYPES.SOME_ACTION, someSaga);}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
ES6-Generatorsfunction* generator (i) {
yield i; i = i + 5;
yield i;}
let g = generator(3);g.next(); // {value: 3, done: false}g.next(); // {value: 8, done: false}g.next(); // {value: undefined, done: true}
Bi-directional ES6-Generatorsfunction* generator () {
let i = yield; i = i + 5;
yield i;}
let g = generator();g.next(); // {value: undefined, done: false}g.next(3); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
Bi-directional ES6-Generatorsfunction* generator () {
let i = yield; i = i + 5;
yield i;}
let g = generator();g.next(); // {value: undefined, done: false}g.next(3); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
Bi-directional ES6-Generatorsfunction* generator () {
let i = yield; i = i + 5;
yield i;}
let g = generator();g.next(); // {value: undefined, done: false}g.next(3); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
Bi-directional ES6-Generatorsfunction* generator () {
let i = yield; i = i + 5;
yield i;}
let g = generator();g.next(); // {value: undefined, done: false}g.next(3); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
Bi-directional ES6-Generatorsfunction* generator () {
let i = yield; i = i + 5;
yield i;}
let g = generator();g.next(); // {value: undefined, done: false}g.next(3); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
Bi-directional ES6-Generatorsfunction* generator () {
let i = yield; i = i + 5;
yield i;}
let g = generator();g.next(); // {value: undefined, done: false}g.next(3); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
Bi-directional ES6-Generatorsfunction* generator () {
let i = yield; i = i + 5;
yield i;}
let g = generator();g.next(); // {value: undefined, done: false}g.next(3); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
Bi-directional ES6-Generatorsfunction* generator () {
let i = yield; i = i + 5;
yield i;}
let g = generator();g.next(); // {value: undefined, done: false}g.next(3); // {value: 8, done: false}g.next(); // {value: undefined: done, true}
Combining Generatorsfunction* anotherGenerator(i) { yield i + 1; yield i + 2;}
function* generator(i) { yield i; yield* anotherGenerator(i); yield i + 10;}
let g = generator(10);
g.next().value; // 10g.next().value; // 11g.next().value; // 12g.next().value; // 20
Back to Redux-Sagafunction* someSaga() { yield put(someActionPending()); try { const result = yield call(asyncFunction); yield put(someActionSuccess(result)); yield* followUpSaga(); } catch (error) { yield put(someActionError(error)); }}
function* watchSomeSaga() { yield takeEvery(TYPES.TRIGGER_ACTION, someSaga);}
Saga Effectsfunction* someSaga() { yield put(someActionPending()); try { const result = yield call(asyncFunction); yield put(someActionSuccess(result)); yield* followUpSaga(); } catch (error) { yield put(someActionError(error)); }}
function* watchSomeSaga() { yield takeEvery(TYPES.TRIGGER_ACTION, someSaga);}
Examples of effects:
● put dispatches an action
● take waits for an action
● call calls an (async) function
● select gets (partial) state
Saga Combined Effectsfunction* someSaga() { yield put(someActionPending()); try { const result = yield call(asyncFunction); yield put(someActionSuccess(result)); yield* followUpSaga(); } catch (error) { yield put(someActionError(error)); }}
function* watchSomeSaga() { yield takeEvery(TYPES.TRIGGER_ACTION, someSaga);}
Examples of combined effects:
● takeEvery waits for an action,
executes a generator and
waits for the next action
● takeLatest works like
takeEvery, but cancels the
execution of the generator
when another action arrives
Debouncing sagafunction* debounceSaga(action) { yield call(delay, 300); yield put(keyDownAction(action.value));}
function* watchDebounceActionSaga() { yield takeLatest(TYPES.DEBOUNCE_KEY_DOWN_ACTION, debounceSaga);}
Pollingfunction* workerSaga() { const something = yield call(someService, fetchSomething); yield put(someAction(something));}
function* pollingSaga() { while (true) { yield* workerSaga(); yield call(delay, 5000); }}
Testing Live Demo
Concusion
Side effects encapsulated in saga
Power of middleware with concise syntax
Readable and easily testable workflows
Pure actions