In Redux is it better for performance to add a property to the items in the store or to calculate it in the container?
https://softwareengineering.stackexchange.com/questions/409417
-
10-03-2021 - |
Question
I'm writing my first Redux app. In my store, I have ~300-500 Island
objects that I retriev from an API and index by an id
string in an object (being treated like a map). When I'm editing one of these Island
s by setting editId
in the store, the buttons for the other Island
s need to be disabled. I can think of three ways I can do this.
- Have all of the components watch
editId
for changes and check theirIsland.id
against theeditId
(I'm guessing this is very slow) - Add a
disabled
prop to my island component, have the container that maps theIsland
s to components watch foreditId
, and calculatedisabled
for each island on render - Add a
disabled
field to theIsland
objects in the store and update each of these objects when my edit action
My hunch is option 2, as that would definitely be the cleanest approach.
This question is coming from a place of migrating from mobx (which had terrible performance) to redux, and hoping performance improves. If any of the three of these will have virtually the same performance, then I'll choose option 2. I just don't know if there's a redux pattern established that I should be using.
Solution
Making some likely assumptions...
500 objects is not a lot. Calculating a bool on 500 objects is an intrinsically tiny operation.
Your cost is unlikely in the derivation of the boolean prop from your objects.
A common experience is excess expense in the rendering process for those objects. In Redux make sure your changes occur as a single state update in a reducer and not via multiple actions for each object from causing multiple computations of state. If you need to use multiple actions to achieve your goal look into using https://react-redux.js.org/api/batch.
If you are using a single action and there is a single run of all the reducers for these changes then the issue can commonly be in the computation of the state itself. In this case it is likely you are recreating the full object graph for these 500 objects in the store every pass because you are modifying a property of each of those 500 objects. The root object must also be replaced with updated references to those 500 objects.
This in itself is not expensive, but can have expensive rendering implications. As all the references here change it is implied with no optimization that there will be 500 rerenders of components, and depending on how you handle the parent object 500 remounts.
If your island objects correlate to a sizable render it's quickly possible to run into performance issues.
The first link below offers a tool for some insights. The second link is some explanation of handling shouldComponentUpdate. https://github.com/welldone-software/why-did-you-render https://reactjs.org/docs/optimizing-performance.html#shouldcomponentupdate-in-action
I believe your primary goal in all of this should be ensuring that the disabled prop change is only triggering a change once for the disabled prop in the dom. If you still have issues, compare how doing a "fast" vanilla JS "disabled" attribute update of 500 disabled island elements goes. If it is comparable it may just be the cost of doing business with 500 objects that cause renders. If not there is more to understand.