takeEvery and takeLatest. Why? When to use? Use simultaneously? - reactjs

I am not clear in when to use takeEvery and when to use takeLatest ? in redux-saga.
I got a basic difference by reading the official documentation. But what is the use of creating concurrent actions in takeEvery (for example, the user clicks on a Load User button 2 consecutive times at a rapid rate, the 2nd click will dispatch a USER_REQUESTED while the fetchUser fired on the first one hasn't yet terminated)
import { takeEvery } from `redux-saga/effects`
function* fetchUser(action) {
...
}
function* watchFetchUser() {
yield takeEvery('USER_REQUESTED', fetchUser)
}
Can anyone please explain. As I am completely new to redux-saga.
Thanks in advance.

Though #Martin Kadlec's solid answers covers the question, I want to elaborate a bit more on the details and differences on takeEvery and takeLatest and when they might be used so you can derive the possible use-cases of them.
TLDR:
You can use takeEvery when the returns of all previous tasks are needed. For example fetching temperature and humidity data from a weatherstation over a certain period to be stored in a database and displayed as a graph - in this case all previous sagas and their return-values are of interset and not only the latest.
You can use takeLatest if i.E. a internal/external instance or a user of an interface could trigger multiple consecutive actions and only the conclusion of the last value is desireable. A good example would be rapid calls to a broker-API for a live-ticker for stock-values where only the latest/most recent value is of interest.
DETAILED:
Think of takeEvery and takeLatest as helper funtions on top of the lower level API of redux-saga which are wrapping internal operations such as spawning tasks when specific actions are dispatched to the Store. Calling them spawns a saga on each action dispatched to the Store that matches pattern.
takeEvery:
The most common takeEvery function is very similar to redux-thunk in its behaviour and methodology. It's basically a wrapper for yield take of a pattern or channel and yield fork.
The clue about takeEvery is that it allows multiple instances of a defined action/task (such as fetchSomeThing in the example below) to be started concurrently/simultaniously.
Unlike takeLatest you can start a new fetchSomeThing task while one or more previous instances of fetchSomeThing have not yet been completed/terminated, therefore are still pending. Keep in mind that there is no guarantee that the tasks will terminate/complete in the same order they were started. To handle out of order responses, you could use takeLatest.
From the official docs:
takeEvery(pattern, saga, ...args)
Spawns a saga on each action dispatched to the Store that matches pattern.
pattern: String | Array | Function
saga: Function - a Generator function
args: Array - arguments to be passed to the started task. takeEvery will add the incoming action to the argument list (i.e. the action will be the last argument provided to saga)
You can also pass in a channel as argument instead of a pattern resulting in the same behaviour as takeEvery(pattern, saga, ...args).
takeLatest:
The takeLatest helper function in contrast only gets the response of the latest request that was fired and can be seen as a wrapper for yield take of a pattern or channel and an additional if-statement checking if a lastTask is present (a previous task that is still pending), which will then be terminated via a yield cancel and a subsequent yield fork that will spawn the current task/action.
From the official docs:
takeLatest(pattern, saga, ...args)
Will only get the response of the latest request fired.
pattern: String | Array | Function
saga: Function - a Generator function
args: Array - arguments to be passed to the started task. takeLatest will add the incoming action to the argument list (i.e. the action will be the last argument provided to saga)
Similar to takeEvery you can also pass in a channel as argument instead of a pattern.

This is something you really need to think about per use case.
These are some cases when you might use takeEvery.
For sagas that are not asynchronous and so there is no reason to
cancel them. takeLatest would work here as well but it might give
false indication when reading code that there is something to
cancel.
Sometimes when the action differs in some way each time. E.g.
imagine you have a movie and you are adding tags with genre of the
movie. Each time the action is triggered you get a different genre,
even though it is the same action type. The user can add genres
quicker than you get response from the server. But just because you
added multiple genres quickly doesn't mean you want to stop the saga
adding the previous one.
Cheap implementation of when you have the same load action for
multiple different items. E.g. You have list of movies and each has
"load detail" button. (Let's ignore the fact that you should
probably hide or disable the button once the loading starts). The
data are always the same for one movie but differs in between them.
When you click on load detail for movie 1 you don't want to cancel
loading of data for movie 2. Since it is a dynamic list of movies
the action type is the same every time, the difference will be
probably something like id of the movie in the action.
In ideal implementation you should probably cancel the previous load saga for
the same movie/id, but that will require more complicated code and
so if you are doing only some simple app you might decide to ignore
that and just allow to run the sagas for same movie multiple times.
That is why I call it "cheap implementation".

To summarize in a few words,
takeEvery allows concurrent actions to be handled. For example, the user clicks on a Load User button 2 consecutive times at a rapid rate, the 2nd click will dispatch a USER_REQUESTED action while the fetchUser fired on the first one hasn't yet terminated.
takeEvery doesn't handle out of order responses from tasks. There is no guarantee that the tasks will terminate in the same order they were started. To handle out of order responses, you may consider takeLatest.
takeLatest instead start a new fetchUser task on each dispatched USER_REQUESTED action. Since takeLatest cancels any pending task started previously, we ensure that if a user triggers multiple consecutive USER_REQUESTED actions rapidly, we'll only conclude with the latest action
Docu: https://redux-saga.js.org/docs/api/

takeEvery - enables the use of several fetchData objects at the same time.
At a given moment, we can start a new fetchData task while there
are still one or more previous fetchData tasks which have not
yet terminated.
takeLatest - Only one fetchData task can be active at any given moment. It
will also be the work that was started most recently. If a new
fetchData job is started while a previous task is still running,
the previous work will be terminated immediately.

Related

Multiple parallels api call

I'm using redux-saga and redux libraries to handle my project in React.
I'll explain my issue: in one moment the frontend application will dispatch n multiple identical saga "CUSTOM_ACTION" action (expected behaviour). Now I'd like to have only one api calls even the actions are multiple. Take latest option doesn't work.
This my saga code:
function* testWorker() {
// call api only once
}
function* testWatcher() {
yield takeLatest("CUSTOM_ACTION", testWorker);
}
With this configuration I have n api calls, one for each action.
How can I solve my problem?
Thanks in advance to everyone who can help me
The answer kind of depends on what you mean by "in one moment".
If you mean that only one request should be running at a time, you can use the takeLeading effect instead of takeLatest. It will start the request for the first action dispatched an ignore all the others until the request saga is finished.
function* testWatcher() {
yield takeLeading("CUSTOM_ACTION", testWorker);
}
If you mean some specific time, you can use the debounce effect. It will run only a single saga for a given time (once the time is over, with the last action dispatched).
function* testWatcher() {
yield debounce(500, "CUSTOM_ACTION", testWorker);
}
You can run it with 0 for a very short amount of time.
There is also the throttle effect if you just want to limit the amount of requests created.

Chain redux store update

I would like to dispatch an action after a first one has been processed by the reducers.
Here is my use case. My component allows the user to select a list of notes (this list is store in redux). Based on some user actions, a random note can be selected from this list and saved in the store.
In the screenshot you can see buttons. "Select All" and "Unselect All" act on the list of possible note. "Start" pick a note from the list.
The issue I have concern the "reset button". It is supposed to chain "select all" and "start" and I don't know how to do that. I tried a naive:
const reset = function () {
dispatch(selectAll());
dispatch(pickANote());
}
With this example, I am facing what I think is a data race. The second action pick a note from a note updated list.
Digging the internet, I found only cases of action chaining based on API calls with redux thunk. The problem I have is that I don't know how to trigger something when a action is processed (which is obvious with an API call)
So, there is 3 solutions:
I am missing something obvious
I am going where no man has gone before
I am doing something anti-pattern
Any help is welcome.
Alright, I found my answer.
No surprise, I was thinking anti-pattern.
In the redux style guide, there is 2 points that lead me to the solution.
It is strongly recommended to dispatch one action that is processed
by several reducers.
It is strongly recommended to put the logic inside the reducers.
The consequence is that I should dispatch "raw data" and then compute value reducers. Following this path, I am not dependent on the values already in the store for the next updates and so, I do not face any data race.

Problems with architecture of the redux store

I'm developing an application that has several states (reducers). Let's say they are messages, likes, comments (all of them are from the completely different instances so i'm not sure if i should combine them into one state).
Every 30 seconds i make request to the server and i receive response that says which parts of my application have been updated. E.g. i received new messages or new comment.
I don't really know how to handle those responses. First, i can simply let container update all other states, but i don't think that it's a good idea, because every container should have it's own state.
Second, i can create a middleware that will catch every action, find the one with required information and shot another action (e.g. new message). After that reducer of the messages will catch this action. But i'm not sure again if this is a correct approach for two reasons:
Is it okay to shot actions from the middleware (won't it be a bidirectional flow)?
How can i actually do it?
Thanks in advance.
UPD. I did it using middleware, but i'm still not sure if this is a correct way. In my middleware i obtain required data using store.getState()... and then i make store.dispatch(myAction). Is it okay?
It's important to understand that a reducer /= state. ( reducer not equal state )
You should have one state, one store for your application. Use combineReducers to well.. combine reducers to keep everything in one state.
http://redux.js.org/docs/api/combineReducers.html
You need to handle async behaviour, something which is not default by redux and therefore you have to use some kind of middleware - meaning you were on the right track.
Try and use the more common once like:
https://github.com/gaearon/redux-thunk
https://github.com/redux-saga/redux-saga
It's advised to separate the async logic from your app. Meaning you need to init your async calling in the app, but keep the async logic in the store.
Here's a guide by Dan Abramov and Redux-Thunk which is simple and clear:
http://redux.js.org/docs/advanced/AsyncActions.html
Hope it answers you.

In the Flux architecture, how do you create two actions from a single user event?

I think there are three options:
The UI Component calls two ActionCreator methods. Each ActionCreator dispatches a message.
The UI Component calls one ActionCreator method which dispatches a message and calls another ActionCreator method.
The UI Component calls one ActionCreator method which does not dispatch any message, but calls two other ActionCreator methods which each dispatch their own message.
Is there a reason to prefer one of these options over the others? Is there any other option?
This is setter-thinking, and is not the correct way to be thinking about Actions. Actions inform your application, they do not cause side effects.
Stores are in control of your application. They are where all logic resides. Stores cause side effects in response to the information they receive from actions. Actions are like a newspaper. Stores respond to the news.
Actions describe something that happened in the real world. In this case, the user did something. It could instead be that the server responded with some data, or that the browser completed an animation frame. Regardless, it is a singular event that actually happened, not an artificial construct of the code.
What you want here instead is to respond in two different ways to this user event, this single action. Two different stores will respond to the same action, but in different ways.
So you would have this in the event handler:
MyAppActions.userClicked(itemID);
and that would create an action like this:
userClicked: function(itemID) {
MyDispatcher.dispatch({
type: MyAppActions.types.USER_CLICKED,
id: itemID,
});
},
and that would play out in your stores like:
switch (action.type) {
case MyAppActions.types.USER_CLICKED:
this._handleUserClicked(action.id);
break;
// ...
}
In the two stores, the implementation of _handleUserClicked would do things specific to the particular store.
There's no reason to prefer one over another, Eric -- unless you need them to be done in a specific order. If that's the case, you probably want to have the First Action do its thing then call the Second Action (which you identified in No. 2 above). But if there's no ordering, there's no particular reason to prefer any of the three methods you outlined.
Like Hal stated, it depends on what you're using them for.
The UI Component calls two ActionCreator methods. Each ActionCreator dispatches a message.
I think this is the best solution if you're not specifically sure what you'll use the actions for. If there's any chance the methods could be called individually in other circumstances, it will be easier if you have the UI component call two ActionCreator methods.
The UI Component calls one ActionCreator method which dispatches a message and calls another ActionCreator method.
It's a good point that if you need actions to be done in a certain order, you should have one action that calls another to be sure that the first action completes before the second one begins.
The UI Component calls one ActionCreator method which does not dispatch any message, but calls two other ActionCreator methods which each dispatch their own message.
I think this is probably the least useful because it does the same thing as situation 1 but forceably binds those two actions together. Only use this if you'll always need both actions to be executed.

Should flux stores, or actions (or both) touch external services?

Should the stores maintain their own state and have the ability to call network and data storage services in doing so ...in which case the actions are just dumb message passers,
-OR-
...should the stores be dumb recipients of immutable data from the actions (and the actions be the ones that fetch/send data between external sources? Store in this instance would act as view-models and would be able to aggregate / filter their data prior to setting their own state base on the immutable data they were fed by the action.
It seems to me that it should be one or the other (rather than a mix of both). If so, why is one preferred / recommended over the other?
I've seen the flux pattern implemented both ways, and after having done both myself (initially going with the former approach), I believe that stores should be dumb recipients of data from the actions, and that asynchronous processing of writes should live in the action creators. (Async reads can be handled differently.) In my experience, this has a few benefits, in order of importance:
Your stores become completely synchronous. This makes your store logic much easier to follow and very easy to test—just instantiate a store with some given state, send it an action, and check to see if the state changed as expected. Furthermore, one of the core concepts in flux is to prevent cascading dispatches and to prevent multiple dispatches at once; this is very difficult to do when your stores do asynchronous processing.
All action dispatches happen from the action creators. If you handle asynchronous operations in your stores and you want to keep your stores' action handlers synchronous (and you should in order to get the flux single-dispatch guarantees), your stores will need to fire additional SUCCESS and FAIL actions in response to asynchronous processing. Putting these dispatches in the action creators instead helps separate the jobs of the action creators and the stores; furthermore, you don't have to go digging through your store logic to figure out where actions are being dispatched from. A typical asynchronous action in this case might look something like this (change the syntax of the dispatch calls based on the flavor of flux you're using):
someActionCreator: function(userId) {
// Dispatch an action now so that stores that want
// to optimistically update their state can do so.
dispatch("SOME_ACTION", {userId: userId});
// This example uses promises, but you can use Node-style
// callbacks or whatever you want for error handling.
SomeDataAccessLayer.doSomething(userId)
.then(function(newData) {
// Stores that optimistically updated may not do anything
// with a "SUCCESS" action, but you might e.g. stop showing
// a loading indicator, etc.
dispatch("SOME_ACTION_SUCCESS", {userId: userId, newData: newData});
}, function(error) {
// Stores can roll back by watching for the error case.
dispatch("SOME_ACTION_FAIL", {userId: userId, error: error});
});
}
Logic that may otherwise be duplicated across various actions should be extracted into a separate module; in this example, that module would be SomeDataAccessLayer, which handles doing the actual Ajax request.
You need less action creators. This is less of a big deal, but nice to have. As mentioned in #2, if your stores have synchronous action dispatch handling (and they should), you'll need to fire extra actions to handle the results of asynchronous operations. Doing the dispatches in the action creators means that a single action creator can dispatch all three action types by handling the result of the asynchronous data access itself.
I tweeted this question to the devs at Facebook and the answer I got from Bill Fisher was:
When responding to a user's interaction with the UI, I would make the async call in the action creator methods.
But when you have a ticker or some other non-human driver, a call from the store works better.
The important thing is to create an action in the error/success callback so data always originates with actions
The stores should do everything, including fetching data, and signalling to components that the store's data has been updated. Why? Because actions can then be lightweight, disposable and replaceable without influencing important behavior. All important behavior and functionality happen in the store. This also prevents duplication of behavior that would otherwise be copied in two very similar but different actions. The stores are your single source of (handling the) truth.
In every Flux implementation I've seen Actions are basically event strings turned into objects, like traditionally you'd have an event named "anchor:clicked" but in Flux it would be defined as AnchorActions.Clicked. They're even so "dumb" that most implementations have separate Dispatcher objects to actually dispatch the events to the stores that are listening.
Personally I like Reflux' implementation of Flux where there are no separate Dispatcher objects and Action objects do the dispatching themselves.
edit: Facebook's Flux actually fetches in "action creators" so they do use smart actions. They do also prepare the payload using the stores:
https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/actions/ChatMessageActionCreators.js#L27 (line 27 and 28)
The callback on completion would then trigger a new action this time with the fetched data as payload:
https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/utils/ChatWebAPIUtils.js#L51
So I guess that's the better solution.
I'll provide an argument in favor of "dumb" Actions.
By placing the responsibility for collecting view data in your Actions, you couple your Actions to the data requirements of your views.
In contrast, generic Actions, that declaratively describe the intent of the user, or some state transition in your application, allows any Store that responds to that Action to transform the intent, into state tailored specifically for the views subscribed to it.
This lends itself to more numerous, but smaller, more specialized Stores. I argue for this style because
this gives you more flexibility in how views consume Store data
"smart" Stores, specialized for the views that consume them, will be smaller and less coupled for complex apps, than "smart" Actions, on which potentially many views depend
The purpose of a Store is to provide data to views. The name "Action" suggests to me that its purpose is to describe a change in my Application.
Suppose you have to add a widget to an existing Dashboard view, which shows some fancy new aggregate data your backend team just rolled out.
With "smart" Actions, you might need to change your "refresh-dashboard" Action, to consume the new API. However, "Refreshing the dashboard" in an abstract sense has not changed. The data requirements of your views is what has changed.
With "dumb" Actions, you might add a new Store for the new widget to consume, and set it up so that when it receives the "refresh-dashboard" Action type, it sends a request for the new data, and exposes it to the new widget once it's ready. It makes sense to me that when the view layer needs more or different data, the things that I change are the sources of that data: Stores.
gaeron's flux-react-router-demo has a nice utility variation of the 'correct' approach.
An ActionCreator generates a promise from an external API service, and then passes the promise and three action constants to a dispatchAsync function in a proxy/extended Dispatcher. dispatchAsync will always dispatch the first action e.g. 'GET_EXTERNAL_DATA' and once the promise returns it will dispatch either 'GET_EXTERNAL_DATA_SUCCESS' or 'GET_EXTERNAL_DATA_ERROR'.
If you want one day to have a development environment comparable to what you see in Bret Victor's famous video Inventing on Principle, you should rather use dumb stores that are just a projection of actions/events inside a data structure, without any side effect. It would also help if your stores were actually member of the same global immutable data structure, like in Redux.
More explainations here: https://stackoverflow.com/a/31388262/82609

Resources