Skip to content

Commit 7c2dc43

Browse files
committed
docs: update architecture and documentation for useLocalStore and utilities
- Added `useLocalStore` details to architecture and docs. - Expanded file structures to include `devtools`, `subscribeKey`, and `withHistory` utilities. - Refined examples and tutorials for consistency and clarity.
1 parent 591fc99 commit 7c2dc43

3 files changed

Lines changed: 106 additions & 58 deletions

File tree

website/docs/ARCHITECTURE.md

Lines changed: 73 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ flowchart TB
2929
GetterEval["Getters: memoized per-snapshot + cross-snapshot caching"]
3030
end
3131
32-
subgraph layer3 ["Layer 3: React Hook (useStore.ts)"]
32+
subgraph layer3 ["Layer 3: React Hook (react.ts)"]
3333
UseStore["useStore(store, selector?)"]
34+
UseLocalStore["useLocalStore(factory)"]
3435
USES["useSyncExternalStore"]
3536
ProxyCompare["proxy-compare: track which snapshot props selector reads"]
3637
IsChanged["isChanged(prev, next, affected): fine-grained diff"]
@@ -63,45 +64,53 @@ flowchart TB
6364
## File Map
6465

6566
```
66-
packages/store/
67-
├── src/
68-
│ ├── index.ts # Barrel export: createClassyStore, useStore, snapshot, subscribe, getVersion, shallowEqual, Snapshot, reactiveMap, reactiveSet, ReactiveMap, ReactiveSet
69-
│ ├── collections/
70-
│ │ ├── collections.ts # ReactiveMap and ReactiveSet implementations
71-
│ │ └── collections.test.ts # tests: ReactiveMap, ReactiveSet, class store integration
72-
│ ├── core/
73-
│ │ ├── core.ts # Layer 1: Write Proxy — createClassyStore(), subscribe(), getVersion()
74-
│ │ ├── core.test.ts # tests: mutations, batching, methods, getters, arrays
75-
│ │ └── computed.test.tsx # tests: write proxy + snapshot memoization, useStore integration
76-
│ ├── react/
77-
│ │ ├── react.ts # Layer 3: React Hook — useStore()
78-
│ │ ├── react.test.tsx # tests: selector mode, auto-tracked mode, re-render control
79-
│ │ └── react.behavior.test.tsx # tests: batching, set-then-revert, async, multi-component, unmount
80-
│ ├── snapshot/
81-
│ │ ├── snapshot.ts # Layer 2: Immutable Snapshots — snapshot()
82-
│ │ └── snapshot.test.ts # tests: freezing, caching, structural sharing, getters
83-
│ ├── utils/
84-
│ │ ├── index.ts # Barrel export for @codebelt/classy-store/utils: persist
85-
│ │ ├── equality/
86-
│ │ │ ├── equality.ts # shallowEqual
87-
│ │ │ └── equality.test.ts # tests for shallowEqual
88-
│ │ ├── internal/
89-
│ │ │ ├── internal.ts # Internal helpers: isPlainObject, canProxy, findGetterDescriptor, PROXYABLE
90-
│ │ │ └── internal.test.ts # tests for internal helpers
91-
│ │ ├── persist/
92-
│ │ │ ├── persist.ts # persist() utility: storage, transforms, versioning, cross-tab sync
93-
│ │ │ └── persist.test.ts # tests: round-trip, transforms, debounce, migration, merge, SSR, cross-tab
94-
│ ├── types.ts # Shared types: Snapshot<T>, StoreInternal, DepEntry, ComputedEntry
95-
├── package.json
96-
├── tsconfig.json
97-
├── tsdown.config.ts
98-
├── bunfig.toml # Preload happy-dom for React hook tests
99-
├── happydom.ts # happy-dom global registrator
100-
├── README.md # Usage guide
101-
├── ARCHITECTURE.md # This file
102-
├── TUTORIAL.md # Step-by-step tutorial
103-
├── PERSIST_TUTORIAL.md # Persist utility tutorial
104-
└── PERSIST_ARCHITECTURE.md # Persist utility internals
67+
src/
68+
├── index.ts # Barrel export: createClassyStore, useStore, snapshot, subscribe, getVersion, shallowEqual, Snapshot, reactiveMap, reactiveSet, ReactiveMap, ReactiveSet
69+
├── collections/
70+
│ ├── collections.ts # ReactiveMap and ReactiveSet implementations
71+
│ └── collections.test.ts # tests: ReactiveMap, ReactiveSet, class store integration
72+
├── core/
73+
│ ├── core.ts # Layer 1: Write Proxy — createClassyStore(), subscribe(), getVersion()
74+
│ ├── core.test.ts # tests: mutations, batching, methods, getters, arrays
75+
│ └── computed.test.tsx # tests: write proxy + snapshot memoization, useStore integration
76+
├── react/
77+
│ ├── react.ts # Layer 3: React Hook — useStore(), useLocalStore()
78+
│ ├── react.test.tsx # tests: selector mode, auto-tracked mode, re-render control
79+
│ └── react.behavior.test.tsx # tests: batching, set-then-revert, async, multi-component, unmount
80+
├── snapshot/
81+
│ ├── snapshot.ts # Layer 2: Immutable Snapshots — snapshot()
82+
│ └── snapshot.test.ts # tests: freezing, caching, structural sharing, getters
83+
├── utils/
84+
│ ├── index.ts # Barrel export for @codebelt/classy-store/utils: persist, devtools, subscribeKey, withHistory
85+
│ ├── devtools/
86+
│ │ ├── devtools.ts # devtools() utility: Redux DevTools integration, time-travel debugging
87+
│ │ └── devtools.test.ts # tests: connect, disconnect, state sync, time-travel
88+
│ ├── equality/
89+
│ │ ├── equality.ts # shallowEqual
90+
│ │ └── equality.test.ts # tests for shallowEqual
91+
│ ├── history/
92+
│ │ ├── history.ts # withHistory() utility: undo/redo via snapshot stack, pause/resume, configurable limits
93+
│ │ └── history.test.ts # tests: undo, redo, limits, pause/resume
94+
│ ├── internal/
95+
│ │ ├── internal.ts # Internal helpers: isPlainObject, canProxy, findGetterDescriptor, PROXYABLE
96+
│ │ └── internal.test.ts # tests for internal helpers
97+
│ ├── persist/
98+
│ │ ├── persist.ts # persist() utility: storage, transforms, versioning, cross-tab sync
99+
│ │ └── persist.test.ts # tests: round-trip, transforms, debounce, migration, merge, SSR, cross-tab
100+
│ ├── subscribe-key/
101+
│ │ ├── subscribe-key.ts # subscribeKey() utility: single-property subscription with prev/current values
102+
│ │ └── subscribe-key.test.ts # tests: single key changes, prev/current values
103+
├── types.ts # Shared types: Snapshot<T>, StoreInternal, DepEntry, ComputedEntry
104+
package.json
105+
tsconfig.json
106+
tsdown.config.ts
107+
bunfig.toml # Preload happy-dom for React hook tests
108+
happydom.ts # happy-dom global registrator
109+
README.md # Usage guide
110+
ARCHITECTURE.md # This file
111+
TUTORIAL.md # Step-by-step tutorial
112+
PERSIST_TUTORIAL.md # Persist utility tutorial
113+
PERSIST_ARCHITECTURE.md # Persist utility internals
105114
```
106115

107116
## Layer 1: Write Proxy (`core.ts`)
@@ -322,7 +331,7 @@ flowchart TD
322331
- **Selector mode:** `useStore(store, (store) => store.filtered)` gets a stable reference from the memoized snapshot getter. `Object.is` correctly detects "no change" without `shallowEqual`.
323332
- **Auto-tracked mode:** `proxy-compare`'s `isChanged` gets stable references from snapshot getters, reducing false positives.
324333

325-
## Layer 3: React Hook (`useStore.ts`)
334+
## Layer 3: React Hook (`react.ts`)
326335

327336
### Overview
328337

@@ -406,20 +415,36 @@ sequenceDiagram
406415

407416
```mermaid
408417
graph LR
409-
useStore["useStore.ts"] --> core["core.ts"]
410-
useStore --> snapshot["snapshot.ts"]
411-
useStore --> proxyCompare["proxy-compare"]
418+
react["react.ts"] --> core["core.ts"]
419+
react --> snapshot["snapshot.ts"]
420+
react --> proxyCompare["proxy-compare"]
412421
snapshot --> core
413422
snapshot --> types["types.ts"]
414-
snapshot --> utils["utils.ts"]
423+
snapshot --> internal["utils/internal/internal.ts"]
415424
core --> types
416-
core --> utils
425+
core --> internal
417426
index["index.ts"] --> core
418427
index --> snapshot
419-
index --> useStore
420-
index --> utils
428+
index --> react
429+
index --> internal
421430
index --> types
422431
432+
subgraph utilities ["Utilities (utils/)"]
433+
persist["persist.ts"]
434+
devtools["devtools.ts"]
435+
subscribeKey["subscribe-key.ts"]
436+
withHistory["history.ts"]
437+
end
438+
439+
persist --> core
440+
persist --> snapshot
441+
persist --> internal
442+
devtools --> core
443+
devtools --> snapshot
444+
subscribeKey --> core
445+
subscribeKey --> snapshot
446+
withHistory --> core
447+
withHistory --> snapshot
423448
```
424449

425450
## Key Design Decisions

website/docs/PERSIST_ARCHITECTURE.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,15 @@ The key insight: writing `proxy[key] = value` during hydration flows through the
4747
## File Structure
4848

4949
```
50-
packages/store/
51-
src/
52-
index.ts # Existing barrel (unchanged)
53-
utils/
54-
index.ts # Barrel: export { persist } from './persist/persist'
55-
persist/
56-
persist.ts # persist(), types, and all logic
57-
persist.test.ts # tests with mock storage adapters
58-
package.json # "./utils" export entry
59-
tsdown.config.ts # 'src/utils/index.ts' in entry array
50+
src/
51+
index.ts # Existing barrel (unchanged)
52+
utils/
53+
index.ts # Barrel: persist, devtools, subscribeKey, withHistory
54+
persist/
55+
persist.ts # persist(), types, and all logic
56+
persist.test.ts # tests with mock storage adapters
57+
package.json # "./utils" export entry
58+
tsdown.config.ts # 'src/utils/index.ts' in entry array
6059
```
6160

6261
## Internal State

website/docs/index.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,30 @@ const userData = useStore(myStore, (store) => ({
148148
}), shallowEqual);
149149
```
150150

151+
### `useLocalStore(factory)`
152+
153+
Creates a component-scoped reactive store. Each component instance gets its own isolated store, garbage collected on unmount.
154+
155+
```tsx
156+
import {useLocalStore, useStore} from '@codebelt/classy-store/react';
157+
158+
class CounterStore {
159+
count = 0;
160+
increment() { this.count++; }
161+
}
162+
163+
function Counter() {
164+
const store = useLocalStore(() => new CounterStore());
165+
const count = useStore(store, (s) => s.count);
166+
167+
return <button onClick={() => store.increment()}>Count: {count}</button>;
168+
}
169+
```
170+
171+
The factory runs once per mount. Subsequent re-renders reuse the same store instance.
172+
173+
> See the [Local Stores](./TUTORIAL.md#local-stores) section in the Tutorial for persistence patterns and more examples.
174+
151175
### `snapshot(store)`
152176

153177
Creates a deeply frozen, immutable snapshot of the current state. Used internally by `useStore` but also available directly.

0 commit comments

Comments
 (0)