The "It's Just a Hook" State Manager for React.
Turn any React hook into a global store. Zero boilerplate. Full type safety. Automatic lifecycle management.
npm install react-state-customStop writing reducers, actions, and manual providers. If you can write a React hook, you've already written your store.
// 1. Write a standard hook (your store logic)
const useCountState = ({ initial = 0 }) => {
const [count, setCount] = useState(initial)
const increment = () => setCount(c => c + 1)
return { count, increment }
}
// 2. Create a store
export const { useStore } = createStore('counter', useCountState)
// 3. Setup (mount once at root) & Use anywhere
function App() {
return (
<>
<AutoRootCtx /> {/* 👈 The magic that manages your stores */}
<Counter />
</>
)
}
function Counter() {
const { count, increment } = useStore({ initial: 10 })
return <button onClick={increment}>{count}</button>
}That's it. No Provider wrapping per store. No complex setup. Just hooks.
Most state libraries force you to learn a new way to write logic (reducers, atoms, proxies). React State Custom lets you use the React skills you already have.
Define state with useState, useEffect, useMemo. No new syntax to learn.
Components only re-render when the specific data they use changes. Performance is built-in.
Stores are created when needed and destroyed when unused. No more manual cleanup or memory leaks.
Full type inference out of the box. Your IDE knows exactly what's in your store.
Write a hook that returns the data and actions you want to share.
// features/userState.ts
import { useState, useEffect } from 'react'
export const useUserState = ({ userId }: { userId: string }) => {
const [user, setUser] = useState(null)
useEffect(() => {
fetchUser(userId).then(setUser)
}, [userId])
return { user, isLoading: !user }
}Use createStore to generate a hook for your components.
import { createStore } from 'react-state-custom'
import { useUserState } from './features/userState'
export const { useStore: useUserStore } = createStore('user', useUserState)Add <AutoRootCtx /> to your app's root. This component manages all your stores automatically.
// App.tsx
import { AutoRootCtx } from 'react-state-custom'
export default function App() {
return (
<>
<AutoRootCtx />
<YourAppContent />
</>
)
}Need to run multiple independent instances of your application or isolate features? Use StateScopeProvider.
import { AutoRootCtx, StateScopeProvider } from 'react-state-custom'
function App() {
return (
<>
<AutoRootCtx /> {/* Global Scope */}
<MainApp />
<StateScopeProvider>
{/* Isolated Scope - Stores here are independent of Global Scope */}
<IsolatedFeature />
</StateScopeProvider>
</>
)
}Stores used inside StateScopeProvider will be completely isolated from the parent or global scope, even if they share the same store definition.
| Feature | React State Custom | Redux | Context API | Zustand |
|---|---|---|---|---|
| Paradigm | Just Hooks 🪝 | Actions/Reducers | Providers | Store Object |
| Boilerplate | 🟢 None | 🔴 High | 🟡 Medium | 🟢 Low |
| Auto Lifecycle | ✅ Yes | ❌ No | ❌ No | ❌ No |
| Selective Renders | ✅ Automatic | ❌ Manual | ✅ Selectors | |
| Learning Curve | 🟢 Low | 🔴 High | 🟡 Medium | 🟢 Low |
Inspect your state in real-time with the built-in DevTools.
import { DevToolContainer } from 'react-state-custom'
import 'react-state-custom/dist/react-state-custom.css'
<DevToolContainer />Create multiple independent instances of the same store by passing different parameters.
// Creates a unique store for each ID
const { count } = useStore({ id: 'counter-1' })
const { count } = useStore({ id: 'counter-2' })Compose stores just like hooks.
const useCartTotal = () => {
const { items } = useCartStore({})
return items.reduce((total, item) => total + item.price, 0)
}npm install react-state-custom
# or
yarn add react-state-custom- API Reference - Full API documentation.
- Live Demo - Interactive examples.
MIT © Vo Thanh Dat