Quelle est la façon idiomatique de commencer rootSaga?

le projet redux-saga existe depuis assez longtemps, mais il y a encore beaucoup de choses confuses au sujet de cette bibliothèque. Et l'un d'eux est: comment démarrer votre rootSaga. Par exemple, dans le tutoriel pour débutant rootSaga commence par yeilding un tableau de sagas. Comme ceci

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

cependant, dans le utilisation de la saga aides section rootSaga se compose de deux sagas fourchues. Comme ceci:

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

la même façon de commencer rootSaga est utilisé dans l'exemple async dans redux-saga repo. Cependant, si vous regardez des exemples de cartes d'achat et de réalité, vous verrez que rootSagas Il ya un tableau de sagas fourches. Comme ceci:

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

aussi, si vous lisez quelques discussions dans redux-saga issues, vous verrez que certaines personnes suggèrent d'utiliser spawn au lieu de fourche pour rootSaga pour vous protéger de l'application complète de crash si l'une de vos sagas fourchues est annulée en raison d'une certaine exception non manipulée.

Donc, par où commencer votre rootSaga? Et quelles sont les différences entre les existants?

26
demandé sur slava shkodin 2016-09-11 19:01:38

2 réponses

vous pouvez lancer plusieurs sagas racine. Mais toute saga A la capacité de démarrer une autre saga par elle-même. Ainsi il est possible de démarrer une seule saga racine, qui crée les autres sagas.

vous avez juste besoin d'être conscient de la façon dont les erreurs se propagent à la saga parent. Si vous avez une seule Saga racine et une saga enfant écrasée, par défaut l'erreur se propagera au parent qui se terminera, ce qui tuera aussi toutes les autres sagas commencées à partir de ce parent.

C'est à à vous de décider ce comportement. Selon votre application, vous pouvez vouloir avoir un comportement fail fast (rendre l'application entière inutilisable s'il y a un tel problème), ou fail safe, et essayer de faire l'application continuer à fonctionner, même si certaines pièces peuvent avoir des problèmes.

généralement je recommande que vous démarriez plusieurs sagas racine, ou votre saga parent utilise spawn au lieu de fork pour que votre application reste utilisable s'il y a un crash. Notez qu'il est également très facile d'oublier de repérer les erreurs dans certains lieu. Vous ne voulez généralement pas, par exemple, que toute votre application devienne inutilisable s'il y a une seule requête API qui échoue

Modifier: je vous recommande de prendre un coup d'oeil à https://github.com/yelouafi/redux-saga/issues/570

Dans ce redux-saga question, je montre différentes façons de démarrer sagas et l'impact qu'il a sur votre application.

TLDR: c'est comme ça que je démarre habituellement root sagas:

const makeRestartable = (saga) => {
  return function* () {
    yield spawn(function* () {
      while (true) {
        try {
          yield call(saga);
          console.error("unexpected root saga termination. The root sagas are supposed to be sagas that live during the whole app lifetime!",saga);
        } catch (e) {
          console.error("Saga error, the saga will be restarted",e);
        }
        yield delay(1000); // Workaround to avoid infinite error loops
      }
    })
  };
};

const rootSagas = [
  domain1saga,
  domain2saga,
  domain3saga,
].map(makeRestartable);

export default function* root() {
  yield rootSagas.map(saga => call(saga));
}
10
répondu Sebastien Lorber 2018-02-24 10:06:58

comment créer rootSaga?

selon un développeur de noyau de redux-saga [1,2] la façon idiomatique de créer rootSaga est d'utiliser le tous les Effet du Combinator. En outre, s'il vous plaît noter que le rendement des tableaux de sagas est obsolète.

exemple 1

Vous pouvez utiliser quelque chose comme (+)

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),
    ]);
}

exemple 2

tiré de ici

// 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
  ])
}

fourche vs spawn

fourche et spawn permettra à la fois de retour tâche objets. Les tâches fourchues sont joint à parent, alors que les tâches engendrées sont détaché de la part du parent.

  • gestion des Erreurs dans les fourches [lien]:

    les Erreurs de l'enfant tâches bulle automatiquement jusqu'à leurs parents. Si n'importe quelle tâche fourchue soulève une erreur uncaught, puis le parent tâche avorter avec L'erreur de l'enfant et l'arbre de l'exécution du Parent entier (c'est-à-dire tâches fourchues + la tâche principale représentée par l'organisme parent si il est toujours en cours) sera annulée.

  • gestion des erreurs dans les tâches générées [lien]:

    le parent n'attendra pas les tâches détachées à terminer avant de revenir et tous les événements qui peuvent affecter le parent ou la tâche détachée sont complètement indépendants (erreur, annulation).

basé sur ce qui précède, vous pouvez utiliser fork pour les tâches "critiques", i.e. "si cette tâche échoue, veuillez crash de l'ensemble de l'application", et se reproduisent pour "non critique" des tâches, i.e. "si cette tâche échoue, ne pas propager l'erreur à l' parent."

5
répondu np8 2017-12-03 20:47:08