I believe there are mainly two potential problems with this implementation regarding unnecessary rerenders that could lead to potential performance issues.
1. Every time there is a change to the store the top-level component (root node) rerenders, thus the entire App gets rerendered.
2. Because the Provider passes the state down every time there is an update, useContext
will rerender every connected component regardless of that component caring about that change or not.
Note, these issues sound related but they are very different and solving one doesn’t guarantee to solve the other.
The first one is easy to understand. Updates on the root node will make react render the entire tree and run the reconciliation algorithm for everything.
The second one has to do with the fact that useContext
will trigger a rerender for every “connected” component when the Provider updates as stated in the documentation: https://reactjs.org/docs/hooks-reference.html#usecontext.
Side note:
useContext
will trigger a rerender EVEN if there is a Pure Component between the provider and the component (which is AWESOME!!). I’ve tested it ¯\_(ツ)_/¯.
Out of experience, because React is very fast (and even faster on a production build), these issues will go unnoticeable on small to medium sized apps, but the opposite is true for big apps and above.
How can these two issues be solved? Ugly, that is how :(.
The crazy thing is, I was writing this exact same medium post (not joking), but the implementation got more complicated, and I ended up not liking it. Basically, I made useStore
return a memoized subscribe
callback (a never-changing! callback, even if the state changed inside) and when the store updated, it would manually notify the subscribers, this fixed issue #1. Then useConnect
did something similar, it used useContext
ONLY to subscribe and then notified the connected components when there was an update after running doing a shallow compare (===
triple equal). To do this, I had to use useState
to keep a local state inside useConnect
, and call setState
only if the state really changed.
P.S. I did not run your code and all my comments are based on reading your code only. Sorry if I said something you already repeated in your post :).