State management library virtual DOM evaluation and comparison
Highlighted feature: As part of this study I created (and improved upon) a React implementation of Qwik's useStore hook. This creates a signal proxy for any nested object or array (or objects with nested arrays!). See the useStore/nested tab for further information and demonstration.
Technical note: This page is using parallel routes - each of the "tabs" below is a separate route. Click each item and observe the change in the address bar.
This page has been included to compare the efficiency of state updates on virtual DOM updates in a variety of leading state management solutions with a detailed look at Signals. Signals are one of the most recent additions to the state management ecosystem: introduced in Solid JS, adopted (and improved) by Qwik JS, with other frameworks following suit. There is currently no native implementation for React but the Preact extension integrates well, and is used and demonstrated here.
Signals in a nutshell: Signals update UI directly completely bipassing the DOM for the most efficient and reactive UI updates possible. Updating a signal value will update its value in a parent UI without re-rendering its descendent node tree. For complex node trees this is a huge performance gain.
Conclusion of this study: None of the legacy state management solutions tested offer truly reactive state updates and only Signals can update state directly without updating the virtual DOM. e.g. nanostores, recoil, zustand and redux (by default) all update the virtual dom and descendent child nodes when state is changed in a parent, though each does so with varying degrees of effiency. However it should be noted that Redux integrates well with signals which can be used for efficient updates where necessary in any application.
Signals are fully compatible with Redux!
Signals can be fully integrated with redux state and mixed with non-reactive state in the store
This redux store contains two counters - one normal state and the other a signal
Note how incrementing the signal state does not update the child component