react-state-custom 1.0.31 → 1.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # React State Custom
2
2
 
3
- **Simple. Powerful. TypeScript-first.**
3
+ **The "It's Just a Hook" State Manager for React.**
4
4
 
5
- A lightweight global React state management library that combines the simplicity of React hooks with the power of event-driven subscriptions. No boilerplate, no complexity—just pure, performant state management.
5
+ Turn any React hook into a global store. Zero boilerplate. Full type safety. Automatic lifecycle management.
6
6
 
7
7
  [![Demo](https://img.shields.io/badge/Demo-Live-blue?style=flat-square)](https://vothanhdat.github.io/react-state-custom/)
8
8
  [![npm version](https://img.shields.io/npm/v/react-state-custom?style=flat-square)](https://www.npmjs.com/package/react-state-custom)
@@ -14,488 +14,178 @@ npm install react-state-custom
14
14
 
15
15
  🎮 **[Try the Live Demo →](https://vothanhdat.github.io/react-state-custom/)**
16
16
 
17
- ## Quick Start (2 minutes)
17
+ ---
18
18
 
19
- If you already know how to write a component with `useState`, you're moments away from sharing that state everywhere.
19
+ ## The 30-Second Pitch
20
20
 
21
- 1. **Write a plain hook** encapuslate data fetching, derived values, and actions inside a normal React hook.
22
- 2. **Create a root context** – `createRootCtx('feature', useFeatureState)` publishes the hook output into a context namespace.
23
- 3. **Let AutoRoot manage lifecycles** – `createAutoCtx(rootCtx, 150)` registers the store with `<AutoRootCtx />` and (optionally) keeps it alive for a short grace period after the last subscriber unmounts.
24
- 4. **Mount `<AutoRootCtx />` once** – drop it near the top of your tree (wrap it with your own `ErrorBoundary` if desired).
25
- 5. **Consume anywhere** – call the generated `useCtxState` hook and destructure data via `useQuickSubscribe` or any `useDataSubscribe*` helper.
21
+ Stop writing reducers, actions, and manual providers. If you can write a React hook, you've already written your store.
26
22
 
27
23
  ```tsx
28
- const useFeatureState = ({ featureId }: { featureId: string }) => {
29
- const [value, setValue] = useState(0)
30
- const double = useMemo(() => value * 2, [value])
31
- return { value, double, increment: () => setValue(v => v + 1) }
32
- }
33
-
34
- const featureRoot = createRootCtx('feature', useFeatureState)
35
- export const { useCtxState: useFeatureCtx } = createAutoCtx(featureRoot, 250)
36
-
37
- function AppShell() {
38
- return (
39
- <>
40
- <AutoRootCtx Wrapper={ErrorBoundary} debugging={import.meta.env.DEV} />
41
- <Routes />
42
- </>
43
- )
44
- }
45
-
46
- function FeatureMeter({ featureId }: { featureId: string }) {
47
- const ctx = useFeatureCtx({ featureId })
48
- const { value, double, increment } = useQuickSubscribe(ctx)
49
- return (
50
- <section>
51
- <strong>{value}</strong>
52
- <em>{double}</em>
53
- <button onClick={increment}>Add</button>
54
- </section>
55
- )
56
- }
57
- ```
58
-
59
- That’s the entire workflow—no reducers, actions, or provider trees.
60
-
61
- ## Why React State Custom?
62
-
63
- **Zero Boilerplate** • **Type-Safe** • **Selective Re-renders** • **Hook-Based** • **~10KB Bundle**
64
-
65
- React State Custom lets you write state management code that feels natural—because it **is** just React hooks. Use the same hooks you already know (`useState`, `useEffect`, etc.) to create powerful, shared global state without learning new paradigms.
66
-
67
- ### When `useState` + `useEffect` Fall Short
68
-
69
- Even though React hooks are flexible, they start to hurt once state crosses component boundaries:
70
-
71
- - **Prop drilling & manual providers** – every time state needs to be shared, you create a context, memoize values, and remember to wrap trees.
72
- - **Coarse-grained re-renders** – updating one property forces every subscriber of that context to render, even if they don't consume the changed field.
73
- - **Lifecycle bookkeeping** – you manually manage instance lifetimes, clean up effects, and guard against components mounting before providers.
74
- - **Zero visibility** – there's no built-in way to inspect shared state, throttle noisy updates, or keep debugging breadcrumbs.
75
-
76
- React State Custom keeps your favorite hooks but layers on automatic context lifecycles, selective subscriptions, and built-in tooling so you can stay productive as your app grows.
77
-
78
- ## ⚡ Quick Example
79
-
80
- ### Without React State Custom (manual context plumbing)
81
-
82
- ```typescript
83
- const CounterContext = createContext<{
84
- count: number;
85
- increment: () => void;
86
- decrement: () => void;
87
- } | null>(null);
88
-
89
- function CounterProvider({ children }: { children: React.ReactNode }) {
90
- const [count, setCount] = useState(0);
91
- const value = useMemo(
92
- () => ({
93
- count,
94
- increment: () => setCount(c => c + 1),
95
- decrement: () => setCount(c => c - 1),
96
- }),
97
- [count]
98
- );
99
-
100
- return <CounterContext.Provider value={value}>{children}</CounterContext.Provider>;
101
- }
102
-
103
- function useCounter() {
104
- const ctx = useContext(CounterContext);
105
- if (!ctx) throw new Error('CounterProvider missing');
106
- return ctx;
107
- }
108
- ```
109
-
110
- Every consumer re-renders whenever anything in `value` changes, you have to remember to wrap parts of the tree with `CounterProvider`, and tearing this pattern down for parameterized instances gets messy fast.
111
-
112
- ### With React State Custom (hook-first store)
113
-
114
- ```typescript
115
- import { createRootCtx, createAutoCtx, useQuickSubscribe, AutoRootCtx } from 'react-state-custom';
116
-
117
- // 1. Write your state logic using familiar React hooks
118
- function useCounterState() {
119
- const [count, setCount] = useState(0);
120
- const increment = () => setCount(c => c + 1);
121
- const decrement = () => setCount(c => c - 1);
122
-
123
- return { count, increment, decrement };
24
+ // 1. Write a standard hook (your store logic)
25
+ const useCountState = ({ initial = 0 }) => {
26
+ const [count, setCount] = useState(initial)
27
+ const increment = () => setCount(c => c + 1)
28
+ return { count, increment }
124
29
  }
125
30
 
126
- // 2. Create shared context (one line!)
127
- const { useCtxState } = createAutoCtx(createRootCtx('counter', useCounterState));
31
+ // 2. Create a store
32
+ export const { useStore } = createStore('counter', useCountState)
128
33
 
129
- // 3. Add AutoRootCtx to your app root (mount it once near the top of your tree)
34
+ // 3. Setup (mount once at root) & Use anywhere
130
35
  function App() {
131
36
  return (
132
37
  <>
133
- <AutoRootCtx />
38
+ <AutoRootCtx /> {/* 👈 The magic that manages your stores */}
134
39
  <Counter />
135
40
  </>
136
- );
41
+ )
137
42
  }
138
43
 
139
- // 4. Use anywhere in your app
140
44
  function Counter() {
141
- const ctx = useCtxState();
142
- const { count, increment, decrement } = useQuickSubscribe(ctx);
143
-
144
- return (
145
- <div>
146
- <h1>{count}</h1>
147
- <button onClick={increment}>+</button>
148
- <button onClick={decrement}>-</button>
149
- </div>
150
- );
45
+ const { count, increment } = useStore({ initial: 10 })
46
+ return <button onClick={increment}>{count}</button>
151
47
  }
152
48
  ```
153
49
 
154
- > ℹ️ `AutoRootCtx` accepts optional `Wrapper` and `debugging` props. Pass an ErrorBoundary-like component through `Wrapper` to isolate failures, or set `debugging` to `true` to render raw state snapshots in the DOM (handy alongside React DevTools when tracking updates).
50
+ **That's it.** No `Provider` wrapping per store. No complex setup. Just hooks.
155
51
 
156
- `useQuickSubscribe` keeps `Counter` focused on `count`, so even if this context grows with more fields later, the component only re-renders when `count` changes.
52
+ ---
157
53
 
158
- **That's it!** No reducers, no actions, no providers to wrap—just hooks.
54
+ ## 🚀 Why React State Custom?
159
55
 
160
- ## Core Concepts in Plain English
56
+ 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.
161
57
 
162
- - **Contexts on demand** – `Context` extends `EventTarget`, so every state update is just an event dispatch. `getContext` memoizes instances per name and `useDataContext` automatically bumps a counter so unused contexts self-evict shortly after the last consumer unmounts.
163
- - **Publishers** `useDataSource` and `useDataSourceMultiple` publish inside effects to keep renders pure. A registry guards against duplicate publishers fighting over the same key so you get actionable errors instead of stale data.
164
- - **Subscribers** – `useDataSubscribe*` hooks cover single, multiple, debounced, and transformed reads. `useQuickSubscribe` proxies the backing data object so each component subscribes only to the properties it touches.
165
- - **Root factories** – `createRootCtx` runs your headless hook exactly once per parameter set, publishes every returned key, and throws if two roots try to mount with the same resolved name. Parameters are serialized via `paramsToId`, so stick to primitive props (string/number/boolean/bigint/null/undefined) to keep IDs deterministic.
166
- - **Auto orchestration** – Mount `<AutoRootCtx />` once and wire each root through `createAutoCtx`. The auto root listens for subscription requests, mounts/destroys the corresponding root on demand, and optionally keeps them alive for a configurable `timeToClean` window to smooth thrashing.
167
- - **Dev tooling** – `DevToolContainer` watches the memoized context cache, flashes updates in place, and lets you plug in custom renderers so you can diff state right beside your UI.
58
+ ### 💎 Zero Boilerplate
59
+ Define state with `useState`, `useEffect`, `useMemo`. No new syntax to learn.
168
60
 
169
- ## Core Building Blocks (copy & paste ready)
61
+ ### 🎯 Selective Re-renders
62
+ Components only re-render when the specific data they use changes. Performance is built-in.
170
63
 
171
- Familiarity beats theory, so here are the primitives you’ll reach for most often:
64
+ ### 🔄 Automatic Lifecycle
65
+ Stores are created when needed and destroyed when unused. No more manual cleanup or memory leaks.
172
66
 
173
- ### 1. Context – event-driven store
174
- ```typescript
175
- const ctx = useDataContext<MyState>('my-state');
176
- ```
67
+ ### 🛡️ TypeScript First
68
+ Full type inference out of the box. Your IDE knows exactly what's in your store.
177
69
 
178
- ### 2. Data source – publish values
179
- ```typescript
180
- useDataSource(ctx, 'count', count);
181
- ```
70
+ ---
182
71
 
183
- ### 3. Subscribers – pick exact fields
184
- ```typescript
185
- const count = useDataSubscribe(ctx, 'count');
186
- const { count, name } = useDataSubscribeMultiple(ctx, 'count', 'name');
187
- ```
72
+ ## 🛠️ Quick Start
188
73
 
189
- ### 4. Root context – run your hook once
190
- ```typescript
191
- const { Root, useCtxState } = createRootCtx('my-state', useMyState);
192
- ```
74
+ ### 1. Define Your State
75
+ Write a hook that returns the data and actions you want to share.
193
76
 
194
- ### 5. Auto context – mount roots for you
195
77
  ```typescript
196
- const { useCtxState } = createAutoCtx(rootContext);
197
- ```
198
-
199
- ## 🎯 Key Features
200
-
201
- ### 1. **Just React Hooks**
202
- Use `useState`, `useEffect`, `useMemo`, and any other React hooks you already know. No new concepts to learn.
78
+ // features/userState.ts
79
+ import { useState, useEffect } from 'react'
203
80
 
204
- ```typescript
205
- function useUserState({ userId }: { userId: string }) {
206
- const [user, setUser] = useState(null);
207
- const [loading, setLoading] = useState(true);
81
+ export const useUserState = ({ userId }: { userId: string }) => {
82
+ const [user, setUser] = useState(null)
208
83
 
209
84
  useEffect(() => {
210
- fetchUser(userId).then(setUser).finally(() => setLoading(false));
211
- }, [userId]);
212
-
213
- return { user, loading };
85
+ fetchUser(userId).then(setUser)
86
+ }, [userId])
87
+
88
+ return { user, isLoading: !user }
214
89
  }
215
90
  ```
216
91
 
217
- ### 2. **Selective Re-renders**
218
- Components only re-render when the **specific data they subscribe to** changes—not when anything in the state changes.
92
+ ### 2. Create the Store
93
+ Use `createStore` to generate a hook for your components.
219
94
 
220
95
  ```typescript
221
- // Only re-renders when 'user' changes, not when 'loading' changes
222
- const { user } = useDataSubscribeMultiple(ctx, 'user');
96
+ import { createStore } from 'react-state-custom'
97
+ import { useUserState } from './features/userState'
223
98
 
224
- // Or subscribe to multiple fields
225
- const { user, loading } = useDataSubscribeMultiple(ctx, 'user', 'loading');
99
+ export const { useStore: useUserStore } = createStore('user', useUserState)
226
100
  ```
227
101
 
228
- > ⚠️ `useQuickSubscribe` proxies are only readable during render. Destructure the properties you need immediately and avoid storing the proxy in refs, effects, or callbacks.
229
-
230
- ### 3. **Automatic Context Management**
231
- With `AutoRootCtx`, state contexts are automatically created and destroyed as needed. Mount it once near your application root, optionally providing a `Wrapper` (for error boundaries) or enabling `debugging` to render live state snapshots in the DOM—useful context when pairing with React DevTools. No manual provider management required.
232
-
233
- ### 4. **TypeScript First**
234
- Full type inference and type safety throughout. Your IDE knows exactly what's in your state.
235
-
236
- ### 5. **Tiny Bundle Size**
237
- ~10KB gzipped. No dependencies except React.
238
-
239
- ## 🆚 Comparison with Hooks, Redux & Zustand
240
-
241
- | Feature | React State Custom | Plain Hooks (Context) | Redux | Zustand |
242
- |---------|-------------------|-----------------------|-------|---------|
243
- | **Bundle Size** | ~10KB | 0KB (just React) | ~50KB (with toolkit) | ~1KB |
244
- | **Learning Curve** | ✅ Minimal (just hooks) | ⚠️ Familiar APIs, but patterns are DIY | ❌ High (actions, reducers, middleware) | ✅ Low |
245
- | **Boilerplate** | ✅ None | ❌ Manual providers + prop drilling | ❌ Heavy | ✅ Minimal |
246
- | **Type Safety** | ✅ Full inference | ⚠️ Custom per-context typing | ⚠️ Requires setup | ✅ Good |
247
- | **Selective Re-renders** | ✅ Built-in | ❌ Context update = every consumer renders | ⚠️ Requires selectors | ✅ Built-in |
248
- | **DevTools** | ✅ Built-in UI | ❌ None | ✅ Redux DevTools | ✅ DevTools support |
249
- | **Async Support** | ✅ Native (hooks) | ✅ Native (hooks) | ⚠️ Requires middleware | ✅ Native |
250
- | **Context Composition** | ✅ Automatic | ❌ Manual provider trees | ❌ Manual | ⚠️ Manual store combination |
251
-
252
- ### When to Use React State Custom
253
-
254
- ✅ **Choose React State Custom if you:**
255
- - Want to use React hooks for state management without learning new patterns
256
- - Need fine-grained control over component re-renders
257
- - Prefer minimal boilerplate and configuration
258
- - Want automatic context lifecycle management
259
- - Need multiple independent state contexts that don't interfere
260
-
261
- ❌ **Consider Redux if you:**
262
- - Need powerful time-travel debugging (Redux DevTools)
263
- - Have a very large team that benefits from strict architectural patterns
264
- - Already have significant Redux investment
265
-
266
- ❌ **Consider Zustand if you:**
267
- - Want the absolute smallest bundle size
268
- - Need a simple global store without context isolation
269
- - Don't need automatic context lifecycle management
270
-
271
- ## 🔥 Real-World Example: User Authentication
272
-
273
- ```typescript
274
- // authState.ts
275
- function useAuthState() {
276
- const [user, setUser] = useState<User | null>(null);
277
- const [loading, setLoading] = useState(true);
278
-
279
- useEffect(() => {
280
- // Check authentication on mount
281
- checkAuth().then(setUser).finally(() => setLoading(false));
282
- }, []);
283
-
284
- const login = async (email: string, password: string) => {
285
- setLoading(true);
286
- try {
287
- const user = await authService.login(email, password);
288
- setUser(user);
289
- } finally {
290
- setLoading(false);
291
- }
292
- };
293
-
294
- const logout = async () => {
295
- await authService.logout();
296
- setUser(null);
297
- };
298
-
299
- return { user, loading, login, logout };
300
- }
301
-
302
- export const { useCtxState: useAuthState } = createAutoCtx(
303
- createRootCtx('auth', useAuthState)
304
- );
102
+ ### 3. Mount the Root (Once)
103
+ Add `<AutoRootCtx />` to your app's root. This component manages all your stores automatically.
305
104
 
105
+ ```tsx
306
106
  // App.tsx
307
- function App() {
107
+ import { AutoRootCtx } from 'react-state-custom'
108
+
109
+ export default function App() {
308
110
  return (
309
111
  <>
310
112
  <AutoRootCtx />
311
- <Router>
312
- <Header />
313
- <Routes />
314
- </Router>
113
+ <YourAppContent />
315
114
  </>
316
- );
317
- }
318
-
319
- // Header.tsx - Only re-renders when user changes
320
- function Header() {
321
- const ctx = useAuthState();
322
- const { user, logout } = useQuickSubscribe(ctx);
323
-
324
- return (
325
- <header>
326
- {user ? (
327
- <>
328
- <span>Welcome, {user.name}</span>
329
- <button onClick={logout}>Logout</button>
330
- </>
331
- ) : (
332
- <Link to="/login">Login</Link>
333
- )}
334
- </header>
335
- );
336
- }
337
-
338
- // ProtectedRoute.tsx - Only re-renders when loading or user changes
339
- function ProtectedRoute({ children }) {
340
- const ctx = useAuthState();
341
- const { user, loading } = useDataSubscribeMultiple(ctx, 'user', 'loading');
342
-
343
- if (loading) return <Spinner />;
344
- if (!user) return <Navigate to="/login" />;
345
-
346
- return children;
115
+ )
347
116
  }
348
117
  ```
349
118
 
350
- **Compare with Redux:**
351
- ```typescript
352
- // Redux requires: action types, action creators, reducers, thunks/sagas
353
- // React State Custom: just write a hook! ✨
354
- ```
355
-
356
- ## 🚀 Advanced Features
119
+ ### 🎭 Isolated State
357
120
 
358
- Once you have a store running, layer in these power-ups as needed.
121
+ Need to run multiple independent instances of your application or isolate features? Use `StateScopeProvider`.
359
122
 
360
- ### Developer Tools
361
- Visual debugging component to inspect all your context data in real-time:
362
-
363
- ```typescript
364
- import { DevToolContainer } from 'react-state-custom';
365
- import 'react-state-custom/dist/react-state-custom.css';
123
+ ```tsx
124
+ import { AutoRootCtx, StateScopeProvider } from 'react-state-custom'
366
125
 
367
126
  function App() {
368
127
  return (
369
128
  <>
370
- <AutoRootCtx />
371
- <YourAppContent />
372
- <DevToolContainer />
129
+ <AutoRootCtx /> {/* Global Scope */}
130
+ <MainApp />
131
+
132
+ <StateScopeProvider>
133
+ {/* Isolated Scope - Stores here are independent of Global Scope */}
134
+ <IsolatedFeature />
135
+ </StateScopeProvider>
373
136
  </>
374
- );
137
+ )
375
138
  }
376
139
  ```
377
140
 
378
- The toggle reveals a bottom-docked inspector that now uses resizable split panes powered by `@uiw/react-split`. Drag the gutter to adjust how much space the context list or detail view occupies while keeping your application visible above.
379
-
380
- **Custom data viewer with rich object visualization:**
381
- ```typescript
382
- import { DataViewComponent } from 'react-state-custom';
383
- import { ObjectView } from 'react-obj-view';
384
- import 'react-obj-view/dist/react-obj-view.css'; // Required for ObjectView styling
385
-
386
- const CustomDataView: DataViewComponent = ({ name, value }) => {
387
- return <ObjectView name={name} value={value} expandLevel={2} />;
388
- };
141
+ Stores used inside `StateScopeProvider` will be completely isolated from the parent or global scope, even if they share the same store definition.
389
142
 
390
- <DevToolContainer Component={CustomDataView} />
391
- ```
143
+ ---
392
144
 
393
- Pass `children` to `DevToolContainer` to customize the floating toggle button label (for example `<DevToolContainer>State Inspector</DevToolContainer>`), and import `react-state-custom/dist/react-state-custom.css` once to pick up the overlay styles.
145
+ ## 🆚 Comparison
394
146
 
395
- ### Parameterized Contexts
396
- Create multiple instances of the same state with different parameters:
147
+ | Feature | React State Custom | Redux | Context API | Zustand |
148
+ |:---|:---:|:---:|:---:|:---:|
149
+ | **Paradigm** | Just Hooks 🪝 | Actions/Reducers | Providers | Store Object |
150
+ | **Boilerplate** | 🟢 None | 🔴 High | 🟡 Medium | 🟢 Low |
151
+ | **Auto Lifecycle** | ✅ Yes | ❌ No | ❌ No | ❌ No |
152
+ | **Selective Renders** | ✅ Automatic | ⚠️ Selectors | ❌ Manual | ✅ Selectors |
153
+ | **Learning Curve** | 🟢 Low | 🔴 High | 🟡 Medium | 🟢 Low |
397
154
 
398
- ```typescript
399
- function useUserState({ userId }: { userId: string }) {
400
- // State logic here
401
- }
402
-
403
- const { useCtxState: useUserCtxState } = createAutoCtx(
404
- createRootCtx('user', useUserState)
405
- );
406
-
407
- // Different instances for different users
408
- function UserProfile({ userId }) {
409
- const ctx = useUserCtxState({ userId }); // Automatic instance per userId
410
- const { user } = useQuickSubscribe(ctx);
411
- return <div>{user?.name}</div>;
412
- }
413
- ```
155
+ ---
414
156
 
415
- > Need to avoid rapid mount/unmount churn? Pass a second argument to `createAutoCtx` (for example `createAutoCtx(rootCtx, 200)`) to keep instances alive for a few extra milliseconds before disposal.
157
+ ## 🧩 Advanced Features
416
158
 
417
- > ⚠️ The props you pass to `createRootCtx`/`useCtxState` must be composed of primitive values (string, number, boolean, bigint, null, or undefined). Objects are rejected so context names stay deterministic—pass IDs instead of raw objects.
159
+ ### 🔌 Developer Tools
160
+ Inspect your state in real-time with the built-in DevTools.
418
161
 
419
- ### Debounced Subscriptions
420
- Optimize performance for frequently changing values:
162
+ ```tsx
163
+ import { DevToolContainer } from 'react-state-custom'
164
+ import 'react-state-custom/dist/react-state-custom.css'
421
165
 
422
- ```typescript
423
- // Re-render at most once per 300ms
424
- const searchQuery = useDataSubscribe(ctx, 'searchQuery', 300);
166
+ <DevToolContainer />
425
167
  ```
426
168
 
427
- ### Transformed Subscriptions
428
- Transform data before using it:
169
+ ### 🆔 Parameterized Stores
170
+ Create multiple independent instances of the same store by passing different parameters.
429
171
 
430
- ```typescript
431
- const userStats = useDataSubscribeWithTransform(
432
- ctx,
433
- 'user',
434
- (user) => ({
435
- fullName: `${user?.firstName} ${user?.lastName}`,
436
- isAdmin: user?.role === 'admin'
437
- })
438
- );
172
+ ```tsx
173
+ // Creates a unique store for each ID
174
+ const { count } = useStore({ id: 'counter-1' })
175
+ const { count } = useStore({ id: 'counter-2' })
439
176
  ```
440
177
 
441
- ## 🎮 Live Examples
442
-
443
- Explore interactive examples in the **[Live Demo](https://vothanhdat.github.io/react-state-custom/)**:
444
-
445
- - **Counter** - Basic state management with increment, decrement, and reset
446
- - **Todo List** - Multiple independent lists with scoped contexts
447
- - **Form Validation** - Real-time validation with error handling
448
- - **Timer** - Side effects and cleanup with millisecond precision
449
- - **Shopping Cart** - Complex state with derived values (total, itemCount)
450
-
451
- Each example includes live code editing with syntax highlighting, powered by Sandpack!
452
-
453
- ## 📖 Documentation
454
-
455
- For complete API documentation, examples, and advanced patterns, see:
456
- - **[API_DOCUMENTATION.md](./API_DOCUMENTATION.md)** - Complete API reference
457
- - **[Live Demo](https://vothanhdat.github.io/react-state-custom/)** - Interactive examples
458
-
459
- ## 🛠️ Development
460
-
461
- ```bash
462
- # Install dependencies
463
- yarn install
464
-
465
- # Run development UI with example selector
466
- yarn dev
467
-
468
- # Run interactive playground with live code editing
469
- yarn dev:playground
470
-
471
- # Build library
472
- yarn build
473
-
474
- # Build demo site
475
- yarn build:demo
178
+ ### ⚡️ Derived State
179
+ Compose stores just like hooks.
476
180
 
477
- # Preview demo locally
478
- yarn preview
181
+ ```tsx
182
+ const useCartTotal = () => {
183
+ const { items } = useCartStore({})
184
+ return items.reduce((total, item) => total + item.price, 0)
185
+ }
479
186
  ```
480
187
 
481
- ### Development Modes
482
-
483
- **`yarn dev`** - Starts a clean development UI with an interactive example selector. Great for:
484
- - Testing all examples in one place
485
- - Quick switching between different examples
486
- - Visual debugging with DevTool component
487
-
488
- **`yarn dev:playground`** - Starts the Sandpack-powered playground with live code editing. Perfect for:
489
- - Creating interactive demos
490
- - Live code editing and experimentation
491
- - Sharing editable examples
492
-
493
- ## 🎓 Learning Path
494
-
495
- 1. **Follow the Quick Start** – build one shared store end-to-end.
496
- 2. **Layer on subscriptions** – swap `useQuickSubscribe` for the more specific `useDataSubscribe*` hooks where it makes sense.
497
- 3. **Optimize when needed** – introduce debounced/transform subscriptions and `createAutoCtx` grace periods to smooth noisy stores.
498
- 4. **Scale up** – add parameterized contexts (one store per ID) and wire the DevTool overlay for visibility.
188
+ ---
499
189
 
500
190
  ## 📦 Installation
501
191
 
@@ -503,18 +193,13 @@ yarn preview
503
193
  npm install react-state-custom
504
194
  # or
505
195
  yarn add react-state-custom
506
- # or
507
- pnpm add react-state-custom
508
196
  ```
509
197
 
510
- ## 🤝 Contributing
198
+ ## 📖 Documentation
511
199
 
512
- Contributions are welcome! Please feel free to submit a Pull Request.
200
+ - **[API Reference](./API_DOCUMENTATION.md)** - Full API documentation.
201
+ - **[Live Demo](https://vothanhdat.github.io/react-state-custom/)** - Interactive examples.
513
202
 
514
203
  ## 📄 License
515
204
 
516
- MIT License - feel free to use in any project.
517
-
518
- ---
519
-
520
- **Made with ❤️ for developers who love React hooks**
205
+ MIT © Vo Thanh Dat
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { Context, getContext, useDataContext, useDataSource, useDataSourceMultiple, useDataSubscribe, useDataSubscribeMultiple, useDataSubscribeMultipleWithDebounce, useDataSubscribeWithTransform } from './state-utils/ctx';
2
2
  export { createRootCtx } from './state-utils/createRootCtx';
3
- export { AutoRootCtx, createAutoCtx } from './state-utils/createAutoCtx';
3
+ export { AutoRootCtx, createAutoCtx, createStore, StateScopeProvider } from './state-utils/createAutoCtx';
4
4
  export { useArrayChangeId } from './state-utils/useArrayChangeId';
5
5
  export { paramsToId, type ParamsToIdRecord, type ParamsToIdInput } from './state-utils/paramsToId';
6
6
  export { useQuickSubscribe } from './state-utils/useQuickSubscribe';