Run Sagas Concurrently with Saga Helpers

Tyler Clark
InstructorTyler Clark

Share this video with your friends

Send Tweet
Published 4 years ago
Updated 3 years ago

Most applications require multiple side effects. So in this lesson, we’ll modify our TakeLatest to accept more than one saga, as well as add another saga helper called TakeEvery.

Instructor: [00:00] Let's create a new action creator called fetchStarWarsPlanets request. We'll give it a type. Then we'll create a new saga by copy and pasting fetchPerson. We'll call it fetchPlanets. We'll update our "person" to "planet" and our fetchUrl as well as update our "data" to "planet" and our type.

[00:22] With this second action creator and saga, we want to make sure our saga helper takeLatest can handle both fetchPerson and fetchPlanets when needed. We want fetchPlanets to be initiated when the fetchStarWarsPlanets request is dispatched to the store.

[00:40] Now let's remember to add our types that we've used into our types file as well as wire up our fetchStarWarsPlanets request action creator inside of our bind actions to dispatch function.

[00:53] Inside of our reducer file, we need to add "planet" to our state as well as make sure we handle the fetchStarWarsPlanet success type with a handler. This handler will get state and action as well as return the current state but update "planet" with our action data.

[01:11] Let's also paste in some CSS for readability. We'll paste that in here, save it, go to our app.js file. We'll copy the mapping portion of "people" and switch it over to "planet." Then we'll also copy the button and make a second one for fetchStarWarsPlanets request. Then we'll change the text and the buttons to "people" and "planets." Perfect.

[01:36] With this second mapping that we added, we're going to show any data that's inside of our StarWarsPlanet reducer. Then when we click on this Load planets button, we want to make sure that our fetchPlanets saga is called with this dispatched fetchStarWarsPlanets request action while making sure that fetchStarWars request still works the same.

[01:57] We'll do this by updating our sagas file. We're bringing "all" from redux-saga, fetchPlanets from our action. Then we'll use that "all" command inside of my saga where we're going to wrap up our takeLatest functions inside of an array. "All" works just as promised at "all" where everything inside of the array will execute with this one yield.

[02:20] With this second takeLatest, we're telling saga to listen for the fetchStarWarsPlanet request type. When it sees this pattern dispatched, it will run fetchPlanets.

[02:29] TakeLatest is called a saga helper. If saga sees a matching type dispatched, and there's already a running provided saga, it will cancel that saga and start a new one, making sure only one or the latest is running at a time. There's another helper called takeEvery where it doesn't care if there's an instance of the provided generator running. It will spin up a new one with each seen type.

[02:55] With our browser open, we can see our two buttons. We want the loadPeople button to call the fetchPerson saga and the loadPlanets to call the fetchPlanets saga. If both are working correctly, they should both print to the screen two sets of data.

Mustafa
Mustafa
~ 4 years ago

Is it correct to say: Promise.all() waits for all events to resolve before returning, but saga's all() does not (otherwise the example would have to wait for both people and planets)

Mustafa
Mustafa
~ 4 years ago

the documentation says: "[all] .. creates an Effect description that instructs the middleware to run multiple Effects in parallel and wait for all of them to complete"

I don't get why mySaga is not halting/waiting until it both takeLatests are met?? Can someone elaborate on this?

function* mySaga() {
  yield all([
    takeLatest(TYPES.FETCH_STAR_WARS_REQUEST, fetchPerson),
    takeLatest(TYPES.FETCH_STAR_WARS_PLANET_REQUEST, fetchPlanets)
  ]);
}
Tyler Clark
Tyler Clarkinstructor
~ 4 years ago

Mustafa, good question! Using the all() effect for this situation is not necessary. You can get the same effect with just a array ([]) by itself. This generator function is not invoked each time a saga is fired. It is statically passed through to the middleware like a configuration object (the sagas are essentially flatten out). It tells the middleware what to look for and which saga to invoke when a specific action creator is fired.