Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

use-s-react

ChristBM76MIT2.0.0TypeScript support: included

useS is a minimal yet powerful React hook for managing both local and global state — with zero boilerplate

react, state management, hook, useSyncExternalStore, zustand alternative, redux alternative, global state, react store, store, complex object state management, lightweight, typescript

readme

use-s-react

npm version npm downloads MIT license

What is useS?

Is a minimal yet powerful React hook for managing both local and global state — with zero boilerplate.

  • 🧠 Feels like useState, so it's instantly familiar.
  • 🚫 No Providers. No Context. No extra setup.
  • Scales globally without wrappers or nested trees.
  • 🧩 Works with any state shape: primitives, arrays, objects, deeply nested structures.
  • 🔁 Supports setState(prev => ...) logic.
  • 🧼 Built with TypeScript and powered by useSyncExternalStore and full-copy for deep reactivity.

It's a native and lightweight alternative to Zustand, Redux Toolkit, React Context, React useReducer and even useState itself — perfect for projects that need power and simplicity without the overhead.

📦 Installation

Install via npm or your preferred package manager:


npm i use-s-react

🚀 Quick Start

🔸 Import the hook


import { useS } from "use-s-react";

🔸 Local state (same as useState)


const [count, setCount] = useS(0);

🔸 Global state (via config object)


const [count, setCount] = useS({ value: 0, key: 'global-counter' });

✅ Best Practice: External Global Store

Use a store.ts to centralize your global state configs:


// store.ts
export const store = {
  globalCounter: {
    value: 0,
    key: 'global-counter',
  },
  globalUser: {
    value: {
      name: "John",
      age: 30,
    },
    key: 'global-user',
  }
};

// Then import and use it:
import { store } from "./store";

const [count, setCount] = useS(store.globalCounter);

♻️ Sharing Global State Between Components

🔸 ComponentA.tsx


import { useS } from "use-s-react";

export function ComponentA() {
  const [count, setCount] = useS({ value: 0, key: 'global-counter' });

  return (
    <div>
      <h3>Component A</h3>
      <p>Count: {count}</p>
      <button onClick={() => setCount(prev => prev + 1)}>Increment</button>
    </div>
  );
}

🔸 ComponentB.tsx


import { useS } from "use-s-react";

export function ComponentB() {
  const [count] = useS({ value: 0, key: 'global-counter' });

  return (
    <div>
      <h3>Component B</h3>
      <p>Count from A: {count}</p>
    </div>
  );
}

🔁 Deep Updates & More

  • Updates are deep-merged using full-copy, preserving nested structures:

setUser({ info: { lang: "es" } }); // doesn't erase other info keys
  • You can also return a new state based on the previous:

setUser(prev => ({
  info: {
    lang: prev === 'en' ? 'es',
    },
  })
);
  • Destructuring deeply

const [{ name, age }, setUser] = useS({
  value: {
    name: "John",
    age: 20
  },
  key: "global-user"
});
  • Infer state typing based on initial value

🧪 Debugging (Optional)

Use debugGlobalStore() to inspect all global state in the console:


import { debugGlobalStore } from "use-s-react";

useEffect(() => {
  debugGlobalStore(); // logs all keys

  debugGlobalStore({ filterKey: "global-user" }); // only "global-user"

  debugGlobalStore({ withConsoleTable: false }); // plain logs
}, []);

✅ Fully compatible with React Native — debugGlobalStore() gracefully falls back to console.log when console.table is not available.

🔍 console.table will be used when possible for better clarity.

🔧 API Summary

useS(initialValue: T) Creates a local state, just like useState (but with super powers).

useS({ value, key }) Makes the state globally available for use by other components. The key must be unique.

📜 License

MIT © ChristBM

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.


[2.0.0] - 2025-06-23

⚠️ Breaking

  • The useS hook now accepts a single parameter instead of three.
  • Previous signature:
    useS(key: string, value: any, global?: boolean)
  • New signature:

    
    useS(value: any)                         // local state
    
    useS({ value: any; key: string })        // global state
    
  • All usage of the previous API must be migrated.

🔄 Changed

  • Simplified the API to reduce cognitive overhead and unify local/global behavior.
  • Refactored setState to handle all data types more predictably and avoid redundant logic.
  • Updates are now only triggered when the new value is different from the current one (deep comparison for objects and known structures).
  • The first component that declares a given key determines the shape of that global state. Subsequent components share the value without overwriting it.

🚀 Improved

  • Performance

    • subscribe, getSnapshot, and setState are memoized for efficiency.
    • State updates avoid cloning unless changes are detected.
  • Developer Experience

    • Improved TypeScript typings.
    • Clearer runtime behavior.
    • Cleaner internal logic and better debugging support.

🐞 Debugging Enhancements

  • debugGlobalStore() now supports optional configuration:

    type DebugOptions = {
      filterKey?: string;
      withConsoleTable?: boolean;
    };
  • Outputs state using console.table (when available) for improved visibility.

  • Falls back to console.log in environments like React Native.
  • Defaults to logging all keys if no filter is provided.

📝 Notes

  • Although this version introduces a breaking API change, it improves maintainability and aligns better with idiomatic React patterns.
  • External helpers (e.g., for managing Set, Map, Array) remain fully compatible and are encouraged for advanced use cases.

[1.0.0] - 2025-06-12

✨ Added

  • Initial release of useS, a custom React hook to manage local and global state using useSyncExternalStore.
  • Support for multiple key values to share global state between components.
  • Optional third parameter global?: boolean to define whether a state is global or local.
  • Simple API inspired by useState:

    const [state, setState] = useS(key: string, value: any, global?: boolean);
  • TypeScript support.

  • Works with both React and React Native.
  • Includes debugGlobalStore() to inspect global store values.

🧪 Basic Example

// Local state
const [count, setCount] = useS('local-counter', 0);

// Global state
const [count, setCount] = useS('shared-counter', 0, true);

📝 Notes

  • Designed to simplify shared state without using Context or heavy libraries.
  • Suitable for lightweight applications or isolated modules that need fast and simple state sharing.