React + Redux, how to render not after each dispatch, but after several?

I am trying to make a few changes to the repository, but not draw until all the changes have been completed. I wanted to do this with decux-thunk.

Here is my action creator:

function addProp(name, value) { return { type:'ADD_PROP', name, value } } function multiGeoChanges(...changes) { // my goal here is to make multiple changes to geo, and make sure that react doesnt update the render till the end return async function(dispatch, getState) { for (let change of changes) { dispatch(change); await promiseTimeout(2000); } } } 

I submit my async action creator as follows:

 store.dispatch(multiGeoChanges(addProp(1, "val1"), addProp(2, "val2"), addProp(3, "val3"))); 

However, this causes a reaction to rendering after each dispatch . I am new to redux-thunk, I have never used asynchronous middleware, but I thought this might help me here.

+12
source share
7 answers

There are ways to achieve the goal:

The classic way:

usually: Actions describe the fact that something happened , but do not indicate how the state of the application changes in response. This is the work of gearboxes. It also means that actions are not setters .

That way, you can describe what happened and accumulate the changes and submit one action something like this:

 const multipleAddProp = (changedProps) =>({ type:'MULTIPLE_ADD_PROP', changedProps }); 

And then respond to the action in the gearbox:

 const geo=(state,action)=>{ ... switch (action.type){ case 'MULTIPLE_ADD_PROP': // apply new props ... } } 

Another way when redrawing is critical:

then you can consider limiting the components that can be overridden when the state changes. For example, you can use shouldComponentUpdate to check whether a component should be displayed or not. You can also use reselection so as not to redraw the connected components after calculating the derived data ...


Custom way: redundant batch action

It works a bit like a transaction.

In this example, subscribers will be notified once:

 import { batchActions } from 'redux-batched-actions'; const multiGeoChanges=(...arrayOfActions)=> dispatch => { dispatch( batchActions(arrayOfActions) ); } 
+6
source

@ Kokovin Vladislav answers correctly. To add additional context:

Redux will notify all subscribers after each submission. To reduce repeated renders, or to send less times, or to use one of several approaches for "packet" mailings and notifications. For more information, see the Redux FAQ on update events: http://redux.js.org/docs/faq/Performance.html#performance-update-events .

I also recently wrote a couple of blog posts that relate to this topic. Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability discuss the pros and cons of using thunks and summarize several ways to handle batch mailings. Practical Redux Part 6: Related Lists, Forms, and Performance describes several key aspects you need to know about Redux performance.

Finally, there are a few more libraries that can help finalize store change notifications. See Store # Store Change Subscriptions in the Redux Add-ons Catalog section for a list of related add-ons. In particular, you may be interested in https://github.com/manaflair/redux-batch , which will allow you to send an array of actions with just one notification.

+8
source

By design, when the state held by the repository changes the view it should display.

You can avoid this by updating the state once.

If you use promises, you can use Promise.all to wait for all promises to resolve, and then send a new action to the repository with the calculated result. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Something like that:

 Promise.all([p1, p2, p3, p4, p5]).then(changes => { dispatch(changes) }, err => { // deal with error }); 

Of course, you will need an action that will concern many details, something like addManyProps , this should update the state once, the result is one render.

+3
source

abbreviations-batch actions Creator of a batch action and its associated reducer of a higher order for reduction, which allows registering subscriber notifications for an array of actions.

0
source

A little late, but I think this is a much more meta.batch solution that allows you to add meta.batch to the actions you would like to combine into one react update.

 import raf from 'raf' import { batchedSubscribe } from 'redux-batched-subscribe' let notify = null let rafId = null const shouldBatch = action => action?.meta?.batch export const batchedSubscribeEnhancer = batchedSubscribe(freshNotify => (notify = freshNotify)) export const batchedSubscribeMiddleware = () => next => action => { const resolved = next(action) if (notify && rafId === null && !shouldBatch(action)) { notify() } else if (!rafId) { rafId = raf(() => { rafId = null notify() }) } return resolved } 

Then connect to your store

 mport { applyMiddleware, compose, createStore } from 'redux' import { batchedSubscribeMiddleware, batchedSubscribeEnhancer } from './batching' const store = createStore( reducer, intialState, compose( batchedSubscribeEnhancer, applyMiddleware(batchedSubscribeMiddleware) ) ) 
0
source

A little late, but I think this is a much more meta.batch solution that allows you to add meta.batch to the actions you would like to combine into one react update. As a bonus, this approach works with asynchronous actions.

 import raf from 'raf' import { batchedSubscribe } from 'redux-batched-subscribe' let notify = null let rafId = null const shouldBatch = action => action?.meta?.batch export const batchedSubscribeEnhancer = batchedSubscribe(freshNotify => (notify = freshNotify)) export const batchedSubscribeMiddleware = () => next => action => { const resolved = next(action) if (notify && rafId === null && !shouldBatch(action)) { notify() } else if (!rafId) { rafId = raf(() => { rafId = null notify() }) } return resolved } 

Then connect to your store

 mport { applyMiddleware, compose, createStore } from 'redux' import { batchedSubscribeMiddleware, batchedSubscribeEnhancer } from './batching' const store = createStore( reducer, intialState, compose( batchedSubscribeEnhancer, applyMiddleware(batchedSubscribeMiddleware) ) ) 
0
source

In reagent redux 7+ dosing is now integrated:

 function myThunk() { return (dispatch, getState) => { // should only result in one combined re-render, not two batch(() => { dispatch(increment()); dispatch(increment()); }) } } 
0
source

Source: https://habr.com/ru/post/1262784/


All Articles