Normally, active community libraries such as React-Redux will keep up with React when there are major updates. React-redux has not officially released a single Hooks API like useRedux, since the react-Redux release was released in a nearly two-month beta and nearly a month after the release of this article. So why is this? Let’s analyze why.

At the end of last year, out of interest, I looked into a wave of redux and React-Redux source code. Apart from understanding the principles, I was curious that react-Redux has so far not supported Hooks. From the perspective of use, there appears a similar:

function ConnectedComponent() {
  const store = useReduxStore()
  const state = useRedux(function mapState())}Copy the code

This code is very understandable, and very much in line with the use of Hooks, in fact there are many unofficial reudx Hooks libraries on the community:

  • react-redux-hooks
  • use-substate
  • react-use-redux

This shows that the community in general is very receptive to Hooks, and everyone should be expecting a true Hooks API from the authorities. So why hasn’t React-Redux released the official Hooks API yet?

I found this issue while looking through the list of Issues in React-Redux. The author gives us a very complete introduction of the growth process of React-Redux from the initial idea to the v6 version. So what are the big changes in v6 compared to V5?

  • usecreateContextTo pass the state
  • onlyProviderSubscribe to store changes
  • No longer to beconnectThe component passes the Store object

The main reasons for the V6 update are as follows:

  • The old context API is about to be removed and will have problems if used with the new context API
  • React is coming soonConcurrent ModeUsing the new Context API, React ensures that the entire tree gets the same state
  • createContextThe default withtop-downData streams no longer need to be implemented by React-Redux itself

That’s the v6 change and why, but so far we don’t seem to see any mention of Hooks. Don’t worry, now it’s business.

While upgrading to V6, the React-Redux team found that the overall performance of v6 was not comparable to v5. The main reason for this performance degradation was not the implementation code of React-Redux, but the implementation of createContent and the fact that React-Redux chose to subscribe to store changes only in the Provider.

Pay attention to

React-redux uses createContext and only subscribs to the Provider. It’s the recommended way to use React-redux, and it’s a sure upgrade from a future-oriented perspective. So don’t ask yourself, why don’t you do it differently?

So how exactly does the so-called performance problem come from? ** The main reason is how createContext notifies subtrees when a value changes. ** Let’s start with a set of performance test comparisons:

This test case comes from React-Redux-Benchmarks, which you can run yourself if you are interested.

As you can see from the graph, the main performance drop in V6 is due to Scripting, which is the time it takes to run JavaScript scripts, which is statistically more than twice as long as v5. It’s much better in Rendering and Painting, but because Scripting has the largest percentage, it’s down slightly overall.

** The root cause is that in the implementation of createContext, we changed the value of the Provider. In this update cycle, React will iterate through all the children of the Provider and mark nodes that are listening on this context. Let subsequent renderings know that this object needs to be updated, even if its props and state are not changed at all. ** The reason why React was implemented in this way can not be explained in a single word. It involves whether there is a method for Fiber to determine whether a node is updated after React 16. I will write a separate article later to explain it.

Due to the reason of appeal, we can imagine that in a React application with many nodes, the total calculation of a Provier like React-Redux placed on the top layer must be very large after the data changes.

In contrast, v5 uses the old Context API. In order to avoid some of the problems caused by this API, the React-Redux team chose to listen for store data changes in WrapperComponent HOC returned by Connect. That is, the connected component may have props changes after a Store change without any need to traverse the subtree.

These are the reasons for the v6 version’s performance decline rather than increase. This is why React’s new Context API is not very suitable for use with frequently changing data. We can imagine the impact on overall performance if we cached all items of a form in the Redux Store as we did before, updating the store every time we entered. React also has an issue on whether and how to design a solution to solve this performance problem. This discussion is very lively, and you may follow it if you are interested.

So far we haven’t said anything about Hooks, aren’t we getting a bit off topic? No, because we already know most of the reasons, which are performance issues with the new Context API. This problem, however, is much more clear when it comes to Hooks.

If we were to encapsulate a Hook like useRedux, we would definitely need to use useContext to get the state provided by the Provider, since the Provider is the only one that subscribes to store changes. Using useContext means that our component is dependent on the context, which means that whenever state changes, the component is marked for update.

As we have always done with react-reudx, we will provide mapState to map the data that the component really needs to listen to, because the store is for the entire application and it is unlikely that any one component will need all the data for the entire application. In this case, in v5, or even in v6 with connect, mapState is executed in HOC for data mapping, and then shallowEqual is used to determine whether there are dependent state changes. If not, there is no need to update the actual component.

But in the case of useContext, even if we provide useRedux with mapState, his execution will still wait until the component actually starts performing updates. That is, we can’t tell React whether it can’t be updated before it updates the component, so the optimizations provided by React are useless.

And once our component starts executing, even if we find that useRedux returns the same map state as the last one, we can’t tell React that the component doesn’t need to be updated to terminate the update. So, this is an optimization that can’t be done at the ** library level. ** We can only optimize through the use of useMemo API, so for students with less development experience, it is likely to lead to frequent useless updates of this component, resulting in a waste of performance.

This is why react-Redux and many libraries have yet to update the Hooks API. Currently, there is no solution to this performance issue. We’ll just have to wait and see.

For now, if you are not aware of these issues with createContent, it is advisable not to put content in context that needs updating frequently (unless there is no other way).

That’s why Hooks are getting so badgered, but the community doesn’t follow so quickly. If you have any questions, just reply to Me, or send Me a question in my AMA, and I’ll review them and answer them.

In addition, some questions raised here will be analyzed in more detail in the future:

  • createContextWhy iterate over all subtree nodes during update
  • React determines whether a node can skip updates

I’m Jocky. If you’re interested in my React analysis, please subscribe to me. I’ll keep up with the React ecology updates and in-depth analysis of React and its ecology.