createGlobalState(initialValue) returns a hook that behaves like useState, except every component calling it shares one value. You call the factory once at module scope; the value it holds lives in a closure, outside React, and any component can read it and write it without a prop or a provider in sight.
That last part is the whole problem. React re-renders in response to its own state setters. A variable in a module closure can change a thousand times and nothing on screen moves, because nothing told React. So a store outside React needs three things wired by hand: a way to read the current value, a way to subscribe to changes, and a way to tell React that a subscribed component is now out of date.
This is the smallest question in the catalog that has all three. No selectors, no reducers, no atoms — one value, shared.
function createGlobalState<S>(initialValue: S): () => [
S,
(next: S | ((prev: S) => S)) => void,
];
Call the factory once, at module scope, and export the hook:
// store.js
const useCount = createGlobalState(0);
Then any component uses it like useState — with no provider and no props:
function Counter() {
const [count, setCount] = useCount();
return <button onClick={() => setCount((n) => n + 1)}>{count}</button>;
}
// A sibling. Nothing connects it to Counter.
function Badge() {
const [count] = useCount();
return <span>{count}</span>; // clicking the button moves this
}
createGlobalState calls are two independent values. The factory is the store; the hook is a window onto it.useState's contract. setValue takes a value or an updater (prev) => next, and its identity is stable, so it is safe in a dependency array.