DEV Community

Oleksandr Demian
Oleksandr Demian

Posted on

šŸ§˜ā€ā™‚ļø A Minimalist’s Guide to Global State in React

When it comes to global state management in React, we’ve all been there—lost in a sea of boilerplate, magic proxies, and sprawling config files.

But what if you didn’t need any of that?

What if you could manage global state in React with:

  • Zero dependencies
  • Type safety out of the box
  • Efficient updates using selectors
  • And all under 0.5KB

Let me introduce you to @odemian/react-store: a tiny, typed, selector-based global state manager that’s built around simplicity and performance.


Why Another State Library?

React already has a ton of state solutions—Redux, Zustand, Jotai, Recoil… the list goes on.

But most apps don’t need the power or complexity that these libraries provide. Often, you just need:

  • Shared state between components
  • Selective subscriptions (don’t re-render unless the data changes)
  • A clean API with full TypeScript support
  • No weird behaviors or magic

That’s where @odemian/react-store comes in.


The Core Idea

At its heart, this library wraps the modern useSyncExternalStore API to give you predictable, stable state updates. Here’s what it gives you:

āœ… Tiny

Roughly 330 bytes after minification and gzip.

🧠 Fully Typed

All store hooks, updaters, and selectors are strongly typed with TypeScript.

šŸŽÆ Selector-Based

You can subscribe to just a slice of your state—only rerendering when that part changes.

āš™ļø Zero Dependencies

It’s just plain TypeScript and React—no magic, no proxies, no extra baggage.


A Real-World Example

Let’s say you want to manage user settings across your app. With @odemian/react-store, it’s as simple as:

// export hook and update function from store creator
export const [useUser, updateUser] = createStore({ name: "", surname: "" });
Enter fullscreen mode Exit fullscreen mode

And in your components:

// read entire user
function User () {
  const user = useUser();
  return <span>{user.name}</span>
}

// or read part of the store
function UserName () {
  const name = useUser(u => u.name);
  // only re-renders if name changes
  return <span>{name}</span>
}
Enter fullscreen mode Exit fullscreen mode

Updating state?


function updateName (name: string) {
  updateUser(u => ({ ...u, name }));
}

function UpdateName () {
  // no need to use hook, update function is available globally and does not require you to subscribe to any state
  return (
    <button onClick={() => updateName("Alice")}>Change name</button>
  );
}
Enter fullscreen mode Exit fullscreen mode

Want to fetch async data on mount?

function AsyncUser () {
  const user = useUser();

  useEffect(() => {
    fetchUser().then(updateUser);
  }, []);

  return <span>{user.name}</span>
}
Enter fullscreen mode Exit fullscreen mode

That’s it. No boilerplate, no destruturing in each component, no reducers, no Provider, no ceremony.


When Should You Use This?

This library shines in small to medium-sized apps or components where:

  • You want simple global state without setup
  • You need fine-grained reactivity
  • You’re tired of boilerplate code
  • You appreciate code you can fully understand in one file

If you’re building a complex app with middleware, dev tools, and advanced debugging needs—Redux or Zustand might still be a better fit. But for most projects? This will feel like a breath of fresh air.


Under the Hood

The implementation is just a few lines of code, but it covers everything you need:

  • A store that can get, subscribe, and update
  • A React hook that lets you read from the store efficiently using selectors
  • No re-renders unless the selected value actually changes
  • Full compatibility with React 18+ using useSyncExternalStore

Try It Yourself

Install it in seconds:

npm install @odemian/react-store
Enter fullscreen mode Exit fullscreen mode

Then create your counter component and store:

import { createStore } from "@odemian/react-store";

const [useCounter, updateCounter] = createStore(0);

export const App = () => {
  const value = useCounter();

  return (
    <div>
      <h1>Count: {value}</h1>
      <button onClick={() => updateCounter(value - 1)}>Decrease</button>
      <button onClick={() => updateCounter(value + 1)}>Increase</button>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

You're now ready to use global state across your app—without bloat or complexity. For more complex examples visit Github page or check this todo app example.


Wrap-Up

Global state in React doesn’t have to be heavyweight or confusing. Sometimes less is truly more.

If you’re looking for a clean, modern alternative to heavy libraries, give @odemian/react-store a try. You might be surprised by how little you actually need to manage state effectively.

Top comments (0)