iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
To share data across React components, a store needs two basic things: a place to keep the current state and a way to notify components when that state changes. In my progression toward nexus-state, I started with that Flux-style foundation, then added actions, subscriptions, and a React adapter to address specific problems. The result is a useful design walkthrough—not proof that a custom store is faster or better for every app.
Why I wanted a shared store
As a developer with a background in UI/UX design, I found that keeping the same data in multiple components became cumbersome. Separate calls to useState create separate copies; lifting state to a common parent can keep it shared, but passing it through props and coordinating updates can become harder as the component tree grows. I wanted one store that components could read and that would notify interested components when its data changed.
As I put it, “When I set out to write the library, what I wanted above all was to understand how state managers work.”
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →The first version: state and subscribers
The simplest useful store has current state, a way to read it, and a list of subscribers to notify after an update. My first version followed a Flux-like publisher/subscriber pattern: the store exposed getState and subscribe, while a React hook subscribed to the store and updated React state when notified.
#1 Best Overall
This divides the work cleanly. The store owns shared data and publishes changes; the React hook connects those changes to component rendering. Components do not need to pass updates through a chain of parent props just to reach other components interested in the same data.
Adding a dispatcher
I next added a dispatcher that accepted known action types. Rather than allowing arbitrary partial-state writes, the store handled recognized actions and notified subscribers when state changed. This made updates more explicit, but it also meant action names and their handling had to be registered and wired into the store.
Why I kept changing state out of Context
Putting changing application state directly in a Context value is convenient, but consumers are notified when that value changes. A component that only needs one field may still be affected by changes to the broader value. That is the limitation my design tried to avoid; it is not a claim that Context is unsuitable for all shared data.
Instead, I used Context to provide a stable store interface, then let consumers read changing state through a subscription. The article shows useSyncExternalStore as the React integration for this approach. Context carries access to the store; the subscription connects a component to updates.
Moving state into a factory closure
A provider-based experiment exposed a lifecycle problem: state recreated during render or reassigned from props will not reliably persist as the store’s long-lived state. I first used a ref to retain it, then moved the ownership into a factory.
In the final core design, a createNexus-style factory keeps state and subscribers inside a closure and returns a stable store API. Each call creates an independent store. Actions are created with access to get and set, so they can read and update the store without a separate dispatcher and string-action switch.
Rank #3
The separation also makes the core independent of React. A separate React entry point, createReactNexus, wraps the core and adds hooks such as use, useSelector, and useRerender. The store’s state and update model do not have to be defined by a React provider.
Recommended Free Tools
What the added features solve
Per-key subscriptions
Listeners can be organized by key, so an update can notify subscribers for changed keys rather than making every selector run for every store update. This adds bookkeeping, and the benchmark results below show why that trade-off may not pay off for a small store.
Actions and batching
Actions are user-defined functions created with access to store reads and writes. Keeping them with the factory avoids spreading registration and wiring across files. The implementation also tracks nested action depth and pending keys: several writes within an action can be collected into one notification pass.
Rank #4
Update-source metadata and persistence
An update can carry a source label, such as server or storage. Subscribers and middleware can inspect that context. It matters for persistence: restoring state from storage is itself a write, and without provenance the persistence logic can react to its own restoration and produce an echo. The persist feature uses the source metadata to distinguish that restore operation.
Middleware and DevTools
Middleware can inspect previous state, next state, and update context. In this design it may replace or cancel an update, and middleware can be removed. A subscription-based Redux DevTools adapter displays the action name, making updates easier to identify while debugging.
What my zustand comparison does—and does not—show
In my 2026 article, I compared nexus-state with zustand 5.0.15. For a React workload of 100 components over 50 keys with 20 single-key updates, zustand produced 2,120 selector runs and 40 renders; nexus-state produced 200 selector runs and the same 40 renders. This is evidence about selector work in that particular workload, not a reduction in renders.
Best Value
I also reported update times for 20,000 updates without React. The figures below are my results for the listed key and component counts; they are not universal timings or an independently reproduced ranking.
| Keys | Components | zustand 5.0.15 | nexus-state |
|---|---|---|---|
| 1 | 1 | 3.5 ms | 5.2 ms |
| 3 | 5 | 3.4 ms | 4.6 ms |
| 5 | 10 | 4.6 ms | 4.8 ms |
| 10 | 20 | 6.3 ms | 5.0 ms |
| 50 | 100 | 32.3 ms | 8.5 ms |
| 100 | 500 | 155.3 ms | 13.1 ms |
The small-store results show the cost of per-key subscriber bookkeeping: in the first three workloads, nexus-state took longer. In the table, its time is lower starting at the 10-key, 20-component workload. That crossover is specific to these reported workloads; the article does not provide enough environment details, repetitions, or full methodology to reproduce the measurements independently or generalize them to other applications.
When this design is useful to study
The value of the walkthrough is its progression: start with state and subscribers, make updates explicit, move state ownership into a stable factory, then add features to meet particular needs. It also illustrates why store mechanics and framework integration can be separate concerns. Whether the added machinery is worthwhile depends on the size and update pattern of the store; the reported small-store timings show that more selective subscriptions are not free.
Free tools Windows power users keep installed
One-click scans. No signup required.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

