Where should I put synchronous side effects associated with actions in redux?

(Note: My question was not clearly written, and I thought about some things incorrectly. The current version of the question is just an attempt to write something that could make the accepted answer useful to as many people as possible).

I want to have an action that adds an item to the store and registers it with an external dependency.

I could use thunk middleware and write

export function addItem(item) { return dispatch => { dispatch(_addItemWithoutRegisteringIt(item)); externalDependency.register(item); }; } 

But subscribers will be notified before the item is registered, and they may depend on its registration.

I could change the order and write

 export function addItem(item) { return dispatch => { externalDependency.register(item); dispatch(_addItemWithoutRegisteringIt(item)); }; } 

But I track the element in external dependency with a unique identifier, which is natural to assign only in the reducer.

I could register an element in the gearbox, but I was given to understand that a very bad way to do side effects in the gearbox can lead to problems on the line.

So what is the best approach?

(My conclusion: there are a number of approaches that could work, but probably the best of my use cases is to store an external dependency descriptor in Redux, not a Redux descriptor in an external dependency.)

+8
javascript redux
source share
2 answers

If you use Redux Thunk middleware , you can encapsulate it in the action creator:

 function addItem(id) { return { type: 'ADD_ITEM', id }; } function showNotification(text) { return { type: 'SHOW_NOTIFICATION', text }; } export function addItemWithNotification(id) { return dispatch => { dispatch(addItem(id)); doSomeSideEffect(); dispatch(showNotification('Item was added.'); }; } 

Developing based on the comments on this answer:

Then maybe this is the wrong template for my case. I do not want subscribers to be called between dispatch(addItem(id)) and doSomeSideEffect() .

In 95% of cases, you should not worry about whether subscribers were involved. Bindings such as React Redux will not be displayed again if the data has not changed.

Do doSomeSideEffect() an acceptable approach into the reducer, or will it have hidden traps?

No, adding side effects to the gearbox is never acceptable. . This contradicts the central premise of Redux and greatly breaks down any instrument in its ecosystem: Redux DevTools , Redux Undo , any solution for recording / playback, tests, etc. Never do that.

If you really need to perform a side effect along with the action, and it is also very important for you that the subscribers are only notified once, just send one action and use [Redux Thunk] to "attach" the side effect to it:

 function addItem(id, item) { return { type: 'ADD_ITEM', id, item }; } export function addItemWithSomeSideEffect(id) { return dispatch => { let item = doSomeSideEffect(); // note: you can use return value dispatch(addItem(id, item)); }; } 

In this case, you will need to process ADD_ITEM from different reducers. There is no need to send two actions without notifying subscribers twice.

Here is one point that I still definitely don’t understand. Dan suggested that thunk middleware could not delay the notification of the subscriber, as this would violate the general use case with asynchronous requests. I still do not understand this.

Consider this:

 export function doSomethinAsync() { return dispatch => { dispatch({ type: 'A' }); dispatch({ type: 'B' }); setTimeout(() => { dispatch({ type: 'C' }); dispatch({ type: 'D' }); }, 1000); }; } 

When do you want your subscriptions to be notified? Certainly, if we notify subscribers only after the release of thunk, we will not notify them at all about C and D

In any case, this is not possible in the current middleware architecture. The mid-tier tool is not intended to prevent bypassing subscribers.

However, what you described can be done with the help of a store enthusiast, such as redux-batched-subscribe . It is not affiliated with Redux Thunk, but it invokes any group of actions sent synchronously to be dropped. Thus, you will receive one notification for A and B , and another notification for C and D However, in my opinion, writing code that relies on this behavior will be fragile.

+10
source share

I'm still in the process of learning Redux; however, my gut instinct says this may be a potential candidate for some customizable middleware ?

+1
source share

All Articles