API Reference
The useS
hook offers a powerful yet minimal API to manage both local and global state in React — with built-in immutability and TypeScript support.
- State type is automatically inferred from the
initialValue
. - Supported types:
null | undefined | number | string | boolean | bigint | function | date | regexp | array | set | map | object
.
🧠 useS(initialValue: T)
Creates a local state, just like useState
, but with enhanced capabilities:
const [state, setState] = useS(0);
🌍 useS({ value: T, key: string })
Creates a global state shared across all components using the same key
.
const [count, setCount] = useS({
value: 0,
key: "global-counter",
});
This is functionally identical to local state, but allows cross-component sharing.
🔑 Global State Rules
key
must be a non-empty unique string.- The first call to
useS()
with a given key sets the initial value. - All subsequent calls with the same key:
- Ignores the creation of a new state.
- Share the same state.
- This ensures state consistency without conflicts or duplication — regardless of where or how many times the key is used.
🧬 Built-In Immutability
- Immutability at entry: useS does not work on the memory reference of the initialValue, it only clones it and creates the state.
- Immutability at exit: useS returns a clone of the actual state, which can be mutated from the component, and this mutation does not affect the original state.
With useS, you will always respect React’s rule of not mutating state because it lets you do so without consequences and then allows you to use that mutation to update it with setState without risk:
const initialValue = new Set([1, 2, 3, 4]);
export function Component() {
const [mySet, setMySet] = useS(initialValue);
const handleAddItem = () => {
mySet.add(5); // mutating mySet state directly
setMySet(mySet); // setting the mutated state to generate a valid change
};
return (
<div>
<p data-testid="display">Items:{Array.from(mySet).join("-")}</p>
<button onClick={handleAddItem}>Add Item</button>
</div>
);
}
🔍 Intelligent Validation and Render Prevention
One of the most powerful optimizations in useS
is its ability to prevent unnecessary re-renders through structural comparison between the previous and the next value.
This means that if the new value is not different or is not supported, the state will not be updated and the component will not be re-rendered.
How Does It Work?
Internally, useS
uses a comparison function based on the data type.
Each supported type has its own mechanism to determine whether a change is valid:
Value Type | Comparison Strategy |
---|---|
All | Object.is(a, b) . |
Date | Compares timestamps using getTime() . |
RegExp | Compares source and flags . |
Set | Recursively compares each value. |
Map | Recursively compares each key and value. |
Array | Recursively compares each element. |
Object | Recursively compares keys and values, including nested ones. |
This allows you to handle complex structures without external libs or manual hacks like JSON.stringify
.
⚠️ Exceptions
- Functions:
Although you can include functions as part of your state these are compared by reference. Every time a key is updated with a function value, it is likely to trigger a state update and re-render.
This behavior is consistent with how React handles functions.
- Initialization values:
null | undefined | [] | {} | new Set() | new Map()
The validation function recognizes the previous common initialization values, allowing them to be assigned to the state. In addition, if the previous value is one of these, it allows the next value to be assigned to the state, checking that it is a compatible value.
Summary
Feature | Status | Notes |
---|---|---|
Local state | ✅ Complete | Same API as useState |
Global state | ✅ Complete | Shared by key , no Provider required |
TypeScript support | ✅ Complete | Fully inferred, no manual typing needed |
Automatic immutability | ✅ Complete | Deep cloning at the entrance and exit |
Avoid Unnecessary re-renders | ✅ Complete | Reference or deep value comparison with type validation |
Derived state support | ✅ Complete | Supports computed state via function properties |
React 18 compatibility | ✅ Complete | Uses useSyncExternalStore |
Web & React Native | ✅ Complete | Compatible with both |
Bundle size | ✅ Small | 22.9kB Unpacked Size |
Boilerplate-free | ✅ Complete | No context, no Provider, no setup |
DevTools/debugging | ⚠️ Partial | debugGlobalStore() available via console |
Built-in persistence | ❌ Not yet | Planned for future versions |
Ready to see it in action?
Explore real-world Examples to see how useS
can simplify your components.