Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
770 views
in Technique[技术] by (71.8m points)

redux saga - What is the idiomatic way of starting rootSaga?

redux-saga project has been existing for a pretty long time now, but still there are a lot of confusing things about this library. And one of them is: how to start your rootSaga. For example, in the beginner tutorial rootSaga is started by yeilding an array of sagas. Like this

export default function* rootSaga() {
  yield [
    helloSaga(),
    watchIncrementAsync()
  ]
}

However, in the using saga helpers section rootSaga consists of two forked sagas. Like this:

export default function* rootSaga() {
  yield fork(watchFetchUsers)
  yield fork(watchCreateUser)
}

The same way of starting rootSaga is used in async example in redux-saga repo. However, if you check real-world and shopping-card examples, you'll see that rootSagas there yeild an array of forked sagas. Like this:

export default function* root() {
  yield [
    fork(getAllProducts),
    fork(watchGetProducts),
    fork(watchCheckout)
  ]
}

Also, if you read some discussions in redux-saga issues, you'll see that some people suggest to use spawn instead of fork for rootSaga to guard you application from complete crashing if one of your forked sagas is canceled because of some unhandled exception.

So, which way is the most right way to start your rootSaga? And what are the differences between the existing ones?

question from:https://stackoverflow.com/questions/39438005/what-is-the-idiomatic-way-of-starting-rootsaga

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

How to create rootSaga?

According to a core developer of redux-saga [1,2] the idiomatic way to create rootSaga is to use the all Effect Combinator. Also, please note that yielding arrays from sagas is deprecated.

Example 1

You could use something like this (+all)

import { fork, all } from 'redux-saga/effects';
import firstSaga from './firstSaga';
import secondSaga from './secondSaga';
import thirdSaga from './thirdSaga';

export default function* rootSaga() {
    yield all([
        fork(firstSaga),
        fork(secondSaga),
        fork(thirdSaga),
    ]);
}

Example 2

Taken from here

// foo.js
import { takeEvery } from 'redux-saga/effects';
export const fooSagas = [
  takeEvery("FOO_A", fooASaga),
  takeEvery("FOO_B", fooBSaga),
]

// bar.js
import { takeEvery } from 'redux-saga/effects';
export const barSagas = [
  takeEvery("BAR_A", barASaga),
  takeEvery("BAR_B", barBSaga),
];

// index.js
import { fooSagas } from './foo';
import { barSagas } from './bar';

export default function* rootSaga() {
  yield all([
    ...fooSagas,
    ...barSagas
  ])
}

fork vs. spawn

fork and spawn will both return Task objects. Forked tasks are attached to parent, whereas spawned tasks are detached from the parent.

  • Error handling in forks [link]:

    Errors from child tasks automatically bubble up to their parents. If any forked task raises an uncaught error, then the parent task will abort with the child Error, and the whole Parent's execution tree (i.e. forked tasks + the main task represented by the parent's body if it's still running) will be cancelled.

  • Error handling in spawned tasks [link]:

    The parent will not wait for detached tasks to terminate before returning and all events which may affect the parent or the detached task are completely independent (error, cancellation).

Based on above, you could, use fork for "mission critical" tasks, i.e. "if this task fails, please crash the whole app", and spawn for "not critical" tasks, i.e. "if this task fails, do not propagate the error to the parent".


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...