Which redux middleware should I choose? - javascript

Following the guide, I came to a sorts of middlewares are there for redux application.
Redux Thunk, Redux Promise, Redux Promise Middleware, Redux Observable, Redux Saga, Redux Pack
It is just a matter of preference around which middleware we choose. But I'm not asking for choosing a convention.
I would like to know if there are any differences between them like performance, browser support, use cases, etc. Or anything else that I'm missing with. I tried a hard research for these but not able to find any article.
So that I can consider choosing a middleware for my application. It will also be great for me to choose middleware if I know the particular use case with different middlewares.
Or, all middlewares are just conventions and I may choose any one of them for any kind of redux application (small or large)?

To be able to choose one of these libraries we must take into account whether we are building a small or large application. Usability, code standards, and JavaScript knowledge may also be considered. All of them are similar.
redux-thunk​
Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. It incorporates the methods dispatch and getState as parameters.
​redux-saga​
redux-saga is a library that aims to make application side effects (i.e. asynchronous like data fetching and impure procedures such as accessing the browser cache) in a manageable and efficient way to execute. It's simple to test as it uses the ES6 feature called generators, making the flow easy to read as synchronous code.
​redux-observable​
redux-observable is a middleware for redux that is inspired by redux-thunk. It allows developers to dispatch a function that returns an Observable, Promise or iterable of action(s). When the observable emits an action, or the promise resolves an action, or the iterable gives an action out, that action is then dispatched as usual.
And others directly from their github source:
redux-promise
The middleware returns a promise to the caller so that it can wait for the operation to finish before continuing. This is especially useful for server-side rendering.
redux-promise-middleware
Redux promise middleware enables robust handling of async action creators in Redux: it accepts a promise and dispatches pending, fulfilled and rejected actions.
The middleware can also be combined with Redux Thunk to chain action creators.
redux-pack
redux-pack is a library that introduces promise-based middleware that allows async actions based on the lifecycle of a promise to be declarative.
Async actions in redux are often done using redux-thunk or other middlewares. The problem with this approach is that it makes it too easy to use dispatch sequentially, and dispatch multiple "actions" as the result of the same interaction/event, where they probably should have just been a single action dispatch.
This can be problematic because we are treating several dispatches as all part of a single transaction, but in reality, each dispatch causes a separate rerender of the entire component tree, where we not only pay a huge performance penalty, but also risk the redux store being in an inconsistent state.
redux-pack helps prevent us from making these mistakes, as it doesn't give us the power of a dispatch function, but allows us to do all of the things we were doing before.

From my personal experience ( I have used most of the middleware you have listed ).
Redux Saga is the way to go. It has a higher learning curve, but once you wrap your head around it, it becomes extremely powerful
Redux Saga
Allows for separation of concerns
Reduced Side Effects
Cancelable tasks ( amazing )
Parallel(like) processing
Once you understand redux saga, it becomes much easier to extend your application.
https://engineering.universe.com/what-is-redux-saga-c1252fc2f4d1

Related

Question about Redux async operations with Thunk

I just recently got introduced to Redux and decided to learn how to implement it. At the moment I'm refactoring some of my previous studying-projects and implementing the global state logic provided by the tool.
The thing is, I've recently stumbled upon the thunk middleware for async actions and got curious about something that's probably a simple concept misunderstanding but that I just can't get over.
So, why would I dispatch an async action? I just can't see the benefits of doing that way instead of waiting for the execution of whatever I'm doing and just then dispatch the action carrying the data I want.
Using a simple fetch call as an example, why would I not do the following:
->await fetch data
->dispatch fetched data
And instead do this:
->dispatch action
->await dispatch action
There's probably some use cases that I don't know of because for me, a beginner, sounds like extra code for something that maybe didn't require it? Idk.
Could someone help me? =)
Yep, as you found, that's Dan Abramov's original explanation of why something like the thunk middleware exists.
I recently wrote a new Redux docs page on Writing Logic with Thunks, which goes into more detail on the purpose behind thunks and how to use them correctly. I'll quote from the "Why Use Thunks?" section:
Thunks allow us to write additional Redux-related logic separate from a UI layer. This logic can include side effects, such as async requests or generating random values, as well as logic that requires dispatching multiple actions or access to the Redux store state.
Redux reducers must not contain side effects, but real applications require logic that has side effects. Some of that may live inside components, but some may need to live outside the UI layer. Thunks (and other Redux middleware) give us a place to put those side effects.
It's common to have logic directly in components, such as making an async request in a click handler or a useEffect hook and then processing the results. However, it's often necessary to move as much of that logic as possible outside the UI layer. This may be done to improve testability of the logic, to keep the UI layer as thin and "presentational" as possible, or to improve code reuse and sharing.
In a sense, a thunk is a loophole where you can write any code that needs to interact with the Redux store, ahead of time, without needing to know which Redux store will be used. This keeps the logic from being bound to any specific Redux store instance and keeps it reusable.
The Redux FAQ entry on "why do we use middleware for side effects?" links to additional information on this topic.

What is the difference between a redux middleware and a redux-observable epic?

I would like to understand when it is appropriate to use a redux middleware over a redux-observable epic (and vice versa).
From the redux middleware documentation
It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.
From the redux-observable documentation
While you'll most commonly produce actions out in response to some action you received in, that's not actually a requirement! Once you're inside your Epic, use any Observable patterns you desire as long as anything output from the final, returned stream, is an action.
My understanding is that an action in a redux middleware may or may not hit a reducer and if it does, it may or may not result in a change of state. In an epic you can produce a new action which may or may not hit a reducer or result in a change of state.
It looks like both can be used to enable side effects so the difference between the two is becoming a bit blurry to me.
Question: Is the FRP foundation the only thing that sets them apart or are there specific events in the lifecycle of an application that are better dealt with a classic middleware or an epic?
"Middleware" are a general type of thing that can be used to customize a Redux store. redux-observable is a specific Redux middleware, which lets you use RxJS logic to interact with dispatched actions.

Converting promise-based React app to redux-saga: how do I set React component variables?

I'm a beginner with redux-saga and as a task I thought I'd try to convert a large existing React app from Promises to redux-saga. I'm making some progress, but one issue I came on is that when I used Promises I was able to set component-local variables depending on whether the promise fulfilled or rejected. Now it seems I just "hand over" the request to redux-saga and never know (in the call site) whether it fulfilled or not, and now I don't know (within my component) whether it succeeded or not.
For example, let us say I have this promise-based call which fetches my user's games
getCurrentGamesForUser = (nickname, token) => {
return logic.getGamesForUser(nickname, token)
.then(currentGames => {
this.needToUpdateGamesFlagFromSocketIO = false
this.setState({currentGames})
sessionStorage.setItem('currentGames', JSON.stringify(currentGames))
})
.catch(({message}) => this.onError(message))
}
Here I'm setting the flag this.needToUpdateGamesFlagFromSocketIO -- as well as a sessionStorage variable -- if my promise succeeds.
Now, as I understand it, I would convert this to
getCurrentGamesForUser = (nickname, token) => {
this.props.dispatch(getCurrentGames(nickname,token))
}
and this works fine. If there's an error, that will be sent to the store from the saga and my component will reflect that.
But what do I do about the local flags and the session storage? Do I need to add these to the store as well? That seems a messy way to go, unless I had a separate store for each component, a local store for each component, which also seems messy. I saw some discussion of a similar topic here, https://github.com/redux-saga/redux-saga/issues/907, but there doesn't seem to be an answer. I'm sure I'm missing the "redux way" of handling all this, and so would welcome any guidance.
Redux-Saga is meant to offload all action based triggers outside component to a separate saga scope. So unfortunately there is no straightforward way to implement what you have requested. Although there are some suggested workarounds in the issue tracker you have mentioned.
The primary aim of redux-saga was ease of management of side affects by offloading it to a separate execution context. One of the tradeoff, is communication can only happen through component -> action -> saga -> store -> component. Hence for the above requirement, I believe using redux-saga would be counterproductive.
That said, you can always use redux-saga in combination with other promise / callback based methods such as redux-thunk.
Usecases such as above would be better suited for callback based implementations while complete isolation of side effects to redux would be handled well with redux-saga.

Redux, right way to deal with web API calls

Where ajax calls should be executed when using Redux with Angular 2?
I see two possibilities, first of that Service classes handles ajax call and other asynchronous operations and delegates the resulting Observable result for store to dispatch. This means that store is just responsible to store the byte state of an application, and Actions are mere carriers to transfer the bytes to store, without executing any logic, validation etc. This was my first impression Redux - Just create a new state based of an instruction and a payload, which is a result of an logical operation executed outside of Redux domain.
However, as I continued reading advanced chapters of Redux official documentation (Async actions and middleware), I got impressions that dispatching actions actually could execute logic, and in point of fact ALL program logic SHOULD be executed as a result of dispatching an action.
Now I'm very confused how the Reducers, Actions and store is intended to use, and what is their relation to events, local service calls, web API calls, routing etc.
You can definitely put business logic in your action creators. As I understand it, you want to keep your reducers as pure as possible with no side effects and limited logic.
Good Links:
this issue for more on how actions and reducers work together
this section of the Redux docs for more on API calls and asynchronous Redux

In "Reflux", what purpose do actions serve?

I'm familiarising myself with both Flux architecture, and Reflux - the simpler version, without a dispatcher - for use with ReactJS.
In full Flux, it sounds like actions have (or at least, can be made to have) a definite and non-trivial purpose: they can be used to update external services (eg. save data back to the server via an API), as described in this question: Should flux stores, or actions (or both) touch external services?
However, in Reflux, the actions are definitely just dumb message parsers. So my question is, what purpose do they serve? Why have them at all? What bad things would happen if your Views/Components just called methods on your store directly?
I'm about to convert my little app from Flux to Reflux, and it looks like I'll be moving all the logic currently in my actions over to the store. It seems to me like the actions in Reflux do nothing other than act as a useless middleman between the component and the store. What am I missing?
Besides the ability to listen for an action in any number of stores as pointed out in the OP comments:
Reflux actions can also touch APIs and such, by placing it in the preEmit action hook for example. Typically you'd create an async action, add some async stuff in the preEmit hook, and then call the "completed" or "failed" sub-actions when the async work is done (or has failed). You can also do sync work in the preEmit hook of course. Logging comes to mind.
It's also fully possible to listen to an action in a store and perform the async work in the store, then call .completed or .failed from there, but I think the consensus that has formed is that stores shouldn't do that work, stores should just react to changing data, not perform business logic.
Async actions also work as promises. Of course you could implement your stores to do that as well, but I'd argue that that's a lot of responsibilities for a data store.

Categories