On boot, the app I'm building gets a stream of data from a server. This stream can have hundreds of messages and entities and each message is handled separately.
It takes a tremendous amount of time to dispatch actions after UI has rendered, because every state change re-renders the @connected component.
I wrote a short example that shows dispatching 1000 actions before render (5-15ms) and 500 after render (~2.5s). So this is clearly not a redux issue.
https://jsbin.com/ruziwa/edit?js,console,output
Obviously component doesn't need to re-render every single dispatched action, but re-rendering should be throttled (say, every 50ms). Is there an established approach for that or does it need to be integrated in @connect?
Well, adding
ItemListContainer.prototype.render = _.throttle(ItemListContainer.prototype.render, 20)
really boosts performance.
Updated https://jsbin.com/ruziwa/11/edit?js,console,output
Probably messing with React's methods is not the right approach though.
Try this: Collect those those messages into an array and flush it with store.dispatch in a single tick with every 50ms (or whatever is required). You must use redux-batched-updates to avoid rendering on every dispatch on the tick.
Probably messing with React's methods is not the right approach though.
Yeah that will break sooner or later...
pseudo code
var store = createStoreWithBatchMiddleware();
var messages = [];
stream.on("message", msg) => messages.push(msg));
setInterval(() => {
messages.forEach(msg => store.dispach(handleMessage(msg)));
messages = [];
}, 50);
Thanks! I integrated https://github.com/tappleby/redux-batched-subscribe (redux-batched-updates uses deprecated api)
I used _.debounce, not unstable_batchedUpdates (it didn't seem to work at all)
This is the amazing result: https://jsbin.com/wurower/7/edit?js,console,output
Would it make sense to integrate to react-redux? Or to write a note about it in the docs?
I'm glad it solved your issue but you should note that debouncing and update batching are completely different things.
With debouncing you end up just completely ignoring most of the messages. That can be ok but if your store state requires to see every message, for example you need sum up some numbers from them, that will not work as expected.
React update batching and the setInterval trick I presented will dispatch every message to the store but will only do it batches to avoid excessive rendering.
@epeli not sure I understand the issue, can you please explain with code?
So far it seems that the issue of multiple unnecessary renders is gone, due to debouncing it, and store is filled correctly after every single dispatch action (it doesn't wait for the debouce time to execute a bunch of actions together).
I'm closing as this doesn't appear to be an issue with this repo鈥攔ather an issue with a particular approach. Please feel free to continue discussing!
Most helpful comment
Well, adding
really boosts performance.
Updated https://jsbin.com/ruziwa/11/edit?js,console,output
Probably messing with React's methods is not the right approach though.