🔄 Global State in React Without Context API or External Libraries

·

2 min read

Cover Image for 🔄 Global State in React Without Context API or External Libraries

Managing the global state is a common challenge in React. While tools like Redux, Zustand, or even React’s built-in Context API are popular choices, they can sometimes feel like overkill for simpler use cases.

What if you could share the state between components without any of that?

Let’s build a custom hook that does just that — global state without context, in under 30 lines of code.

âś… When Would You Use This?

  • You need a shared state across a few components

  • You want to avoid boilerplate

  • You don't need advanced features like middleware or persistence

🧠 useGlobalState Implementation

The idea is to make a simple shared store using closure and use subscription pattern -

// globalState.ts
import { useEffect, useState } from 'react';

type Subscriber<T> = (value: T) => void;

function createGlobalState<T>(initialValue: T) {
  let state = initialValue;
  const subscribers = new Set<Subscriber<T>>();

  const setState = (newValue: T) => {
    state = newValue;
    subscribers.forEach((callback) => callback(state));
  };

  const useGlobalState = () => {
    const [localState, setLocalState] = useState(state);

    useEffect(() => {
      const callback = (newValue: T) => setLocalState(newValue);
      subscribers.add(callback);
      return () => subscribers.delete(callback);
    }, []);

    return [localState, setState] as const;
  };

  return useGlobalState;
}

🧪 Example Usage

We can call createGlobalState fn to get a global hook -

const useGlobalCounter = createGlobalState(0);

const ComponentA = () => {
  const [count, setCount] = useGlobalCounter();
  return <button onClick={() => setCount(count + 1)}>Increment A: {count}</button>;
};

const ComponentB = () => {
  const [count, setCount] = useGlobalCounter();
  return <button onClick={() => setCount(count + 1)}>Increment B: {count}</button>;
};

Use both components anywhere in your tree, and they’ll stay in sync without a context provider.

⚠️ Caveats

  • It won’t work well for deep React trees with frequent updates.

  • Use wisely — for complex apps, dedicated state libraries are still a better fit.

đź“Ś Summary

This pattern offers a minimal, dependency-free way to manage shared states in React apps. Great for small to mid-sized apps or feature-level global states — no Context, no boilerplate.

Give it a try and see how far you can go without reaching for Redux or Context. 🚀