Tag: redux

A pretty great use-case for Map in JS

A pretty great use-case for Map in JS

JS Map can store anything as a key, but you rarely need more than a number or string there. Here, I discuss a use-case where I needed something more.

React-Redux: Connecting all children (part 2)

React-Redux: Connecting all children (part 2)

A clearer look into the performance implications of different approaches to connect components to the redux store, backed by real data.

React-Redux: Connecting All Children

React-Redux: Connecting All Children

It appears to be a fairly common notion that having a single connected container component in your react-redux project is a recommended idea for a variety of reasons. The main one being that it was suggested by the main react and redux teams back in the day. [source 1] [source 2]

Experiment (see console): https://jayant.dev/experiments/redux-connections
Code: Version 1 | Version 2
Follow up post: Post Link

They have however admitted since then it having a single top-level connected component was a mistake, although it’s rare to see the store connected to just one top level component now, it’s fairly common to see people recommend not connecting too many components.

So, how many is too many here? 10? 50? 100? 1000? 10000?

I do not know. But I was curious too about the performance cost of connecting too many components. So in one of my projects, I tried connecting upto 11000 components to the store to read their specific resource which was present in an array (looked up by index).

Turns out, that was not a bad idea after all! My application actually worked better because now I was able to pass in props directly to each component from the store that would result in updating only the concerned component, and not every component in the array when I would make a change to one item in the array and then return a new reference to the array.

This is how I would do it:

  1. Connect parent to store, and read the array of objects into it.
  2. Map over the array to render the Item-s, and pass in index as a prop to it.
  3. Connect the Item component to the store. In its mapStateToProps, you will have access to the index prop passed to the component. Return the object at the index you received, from the Array of objects in your store. So this Item component is now only concerned with that one object.
  4. Profit!

Why does this work?

Because while the parent will update and loop whenever items updates, it won’t trigger an update for all the contained Item-s. Because the Item component is only getting an index, and that never changes, so React optimizes that away.

And, the Item components will get the updates resources from the store, specified by their index, so only the object that was updated will trigger a render of its respective component.

To see this in action, go to the experiment page and open the browser console to see how many times an update to any Item component has occurred. You’ll see that for the blue (parent) one, each update logs 10 times, once for each Item, while for the coral (children) one, each update logs only once, for the item that was updated. This is of course, after there already have been 10 logs, once for the first render of each item.

Update:

The code has a second iteration to it where the function to connect store state to component props is modified a bit. Now instead of returning the original items array as-is to the component, only to NOT use its contents inside the parent directly anyway, we now return just the length. That prevents even the parent from rendering on subsequent updates. Why does that work?

Shallow comparisons.

Shallow comparisons happen at at-least the following points:

  1. Component props.
  2. mapStateToProps and mapDispatchToProps

Previously, we were already passing in unchanging props to the Item component, making React not trigger a re-render of every Item that wasn’t being updated. But the parent component itself was being re-rendered, even though it didn’t quite need to because our changes only concerned one specific Item component. This was because we were returning a new instance of the items redux state property.

We changed that to return itemCount, which is just items.length, from the mapStateToProps function passed to the connect HOC. Since items.length would remain the same in our case, a shallow comparison on them will return true, hence a re-render would be avoided at this point.

If you’re not completely convinced that this is a good idea, there’s a data-backed follow-up post to back this up.