Master Global State Management in React with Custom Hooks
Learn how to build a simple global state management solution in React using custom hooks, starting from a basic counter component, extending it with initialization props, synchronizing multiple counters, and finally creating a reusable createGlobalState utility for shared state across components.
Example of developing a counter component, introducing a method to implement global state management using React Hooks.
Simple Counter Component
Below is a simple counter component named
Counterthat starts counting from 0 and increments by one on each click:
<code>const Counter = ({ text }) => {
const [count, setCount] = useState(0);
const addCount = () => setCount(count + 1);
return (
<div onClick={addCount}>
{text}: {count}
</div>
);
};
</code>We can further abstract the above
Counterusing a custom hook
useCounterto implement the counting logic:
<code>const useCounter = (initCount) => {
const [count, setCount] = useState(initCount || 0);
const addCount = () => setCount(count + 1);
return [count, addCount];
};
const Counter = ({ text }) => {
// Use custom hook useCounter
const [count, addCount] = useCounter(0);
return (
<div onClick={addCount}>
{text}: {count}
</div>
);
};
</code>Both implementations produce the same functionality. We can render two counters using the
Countercomponent:
<code>const APP = () => {
return (
<div>
<Counter text="计数器1" />
<Counter text="计数器2" />
</div>
);
};
</code>Result:
Counter with Initial Value
The two counters are independent. By adding an
initCountprop to
Counter, we can set the initial value:
<code>const useCounter = (initCount) => {
const [count, setCount] = useState(initCount || 0);
// Component updates its own count
const addCount = () => setCount(count + 1);
// Reset count when initCount changes
useEffect(() => {
setCount(initCount);
}, [initCount]);
return [count, addCount];
};
const Counter = ({ initCount, text }) => {
const [count, addCount] = useCounter(initCount);
return (
<div onClick={addCount}>
{text}: {count}
</div>
);
};
const APP = () => {
return (
<div>
<Counter initCount={1} text="计数器1" />
<Counter initCount={0} text="计数器2" />
</div>
);
};
</code>Synchronized Counters
To make two counters update synchronously, share the count state in the parent component and pass both the count and a change handler to each counter via an
onChangeprop:
<code>const useCounter = (initCount, onChange) => {
const [count, setCount] = useState(initCount || 0);
const addCount = onChange || (() => setCount(count + 1));
useEffect(() => {
setCount(initCount);
}, [initCount]);
return [count, addCount];
};
const Counter = ({ initCount, onChange, text }) => {
const [count, addCount] = useCounter(initCount, onChange);
return (
<div onClick={addCount}>
{text}: {count}
</div>
);
};
const APP = () => {
const [count, setCount] = useState(0);
const addCount = () => setCount(count + 1);
return (
<div className="App">
<Counter initCount={count} text="计数器1" onChange={addCount} />
<Counter initCount={count} text="计数器2" onChange={addCount} />
</div>
);
};
</code>Result:
We can further simplify by using a single custom hook for global state:
<code>const APP = () => {
const [count, addCount] = useCounter(0);
return (
<div className="App">
<Counter initCount={count} text="计数器1" onChange={addCount} />
<Counter initCount={count} text="计数器2" onChange={addCount} />
</div>
);
};
</code>More General Global State Management
Upgrade the code to a reusable
createGlobalStateutility for simple global state management:
<code>const createGlobalState = (initialState) => {
let globalState = initialState;
const listeners = new Set();
const setGlobalState = (nextGlobalState) => {
globalState = nextGlobalState;
listeners.forEach((listener) => listener());
};
const useGlobalState = () => {
const [state, setState] = useState(globalState);
useEffect(() => {
const listener = () => setState(globalState);
listeners.add(listener);
listener();
return () => listeners.delete(listener);
}, []);
return [state, setGlobalState];
};
return {
setGlobalState,
useGlobalState,
};
};
</code>Using
createGlobalStatefor state management:
<code>const { useGlobalState } = createGlobalState(0);
const Counter = ({ text }) => {
const [state, setGlobalState] = useGlobalState();
return (
<div onClick={() => setGlobalState(state + 1)}>
{text}: {state}
</div>
);
};
const App = () => {
const [state] = useGlobalState();
return (
<div className="App">
<Counter text="计数器" />
<div>点击次数:{state}</div>
</div>
);
};
</code>Result:
This simple implementation is limited; for a more complete solution, see the
react-hooks-global-statelibrary, which inspired this article.
KooFE Frontend Team
Follow the latest frontend updates
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.