Building react state manager
Nov 6, 2023
We’re going to build a performant state manager that minimizes unnecessary re-renders and efficiently handles updates. I’ve tried to sketch the concept below—it’s my first attempt, so it might be a bit rough 😅.
Our goal is to pass state to any node in our React component tree and update it efficiently. Only the components that use the state will re-render, while others remain unchanged.
- We initialize a counter with
0
on the right node and pass the same counter to the left node. - We update the counter on the right node to
10
. - We trigger a callback to re-render only the components using the state.
This approach is similar to how the DOM handles events: when an event listener is triggered, only the elements directly listening to it are affected. We treat components as observers of the state, preventing unnecessary re-renders across the application.
Creating the Global State File
First, let’s create a global-state.ts
file inside the src
folder. This file will contain the functions that manage our state.
Get State and Update State
We’ll start by defining a state
function to initialize and manage our state.
- We define a
type
for theset
method, which updates the state value. - The
StateResponse
type specifies the structure of the return value from our state function. - The
StateResponse
uses a genericStateType
.
Next, we implement the set
method, which updates the state. We initialize currentValue
with initialValue
, define the set
function, and return it.
To finalize, we add the get
method, which simply returns the current state value.
Sharing State Between Components
Now, we need to handle how state changes are shared between components using subscriptions and triggers. We start by creating a Set
to store unique subscriber callbacks, which will be called when the state changes.
Trigger Function
The trigger
function registers a callback with the subscribers and returns a function to remove the callback when the component unmounts.
Complete State Function
Here’s the complete implementation of our createState
function, which includes get
, set
, and trigger
methods:
Creating a Custom Hook
Next, we’ll create useGlobalState
, a custom hook that helps us create state and register triggers:
Testing the State Manager
To test our state manager, let’s create two simple components that interact with the global state:
Run the app with Vite or another tool to see it in action.
Improvements and Final Thoughts
Congratulations! You’ve built a basic but effective React state manager. However, there are ways to improve it further. For example, replacing useEffect
with useSyncExternalStore
can enhance performance by synchronizing state updates more efficiently.
If you have any questions or want to explore further, here are some helpful resources: