memorio 4.7.3 → 4.9.5
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 +242 -331
- package/SUMMARY.md +3 -0
- package/index.cjs +87 -147
- package/index.d.ts +1 -0
- package/index.js +46 -100
- package/llms.txt +1 -1
- package/package.json +9 -3
- package/types/env.d.ts +9 -0
- package/types/exports.d.ts +52 -1
- package/types/memorio.d.ts +43 -10
- package/types/memory.d.ts +95 -0
- package/types/schema.d.ts +53 -53
- package/types/sqlite.d.ts +35 -0
- package/markdown/CACHE.md +0 -90
- package/markdown/CHANGELOG.md +0 -161
- package/markdown/DEVTOOLS.md +0 -122
- package/markdown/DISPATCH.md +0 -168
- package/markdown/HISTORY.md +0 -192
- package/markdown/IDB.md +0 -169
- package/markdown/IMPORT.md +0 -139
- package/markdown/INSPECT.md +0 -116
- package/markdown/LOGGER.md +0 -147
- package/markdown/MEMORY.md +0 -155
- package/markdown/OBSERVER.md +0 -200
- package/markdown/PLATFORM.md +0 -265
- package/markdown/SCHEMA.md +0 -169
- package/markdown/SECURITY.md +0 -323
- package/markdown/SESSION.md +0 -154
- package/markdown/STATE.md +0 -153
- package/markdown/STORE.md +0 -164
- package/markdown/TYPED.md +0 -158
- package/markdown/USEOBSERVER.md +0 -259
package/markdown/STORE.md
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
# Store - Memorio
|
|
2
|
-
|
|
3
|
-
> 🖥️ **Browser & Edge**: Uses localStorage for persistence
|
|
4
|
-
> ⚙️ **Node.js/Deno**: Falls back to in-memory storage (not persistent)
|
|
5
|
-
|
|
6
|
-
Store provides persistent localStorage management with a simple API. Data survives page refreshes and browser restarts.
|
|
7
|
-
|
|
8
|
-
## Installation
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install memorio
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
```javascript
|
|
15
|
-
import 'memorio';
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
> **Classic `import`**: `store` is also a named export.
|
|
19
|
-
> `import { store } from 'memorio'` returns the exact same instance as `globalThis.store`.
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Quick Examples
|
|
24
|
-
|
|
25
|
-
### Example 1: Basic Usage
|
|
26
|
-
|
|
27
|
-
```javascript
|
|
28
|
-
// Save data
|
|
29
|
-
store.set('username', 'Mario');
|
|
30
|
-
store.set('score', 1500);
|
|
31
|
-
|
|
32
|
-
// Read data
|
|
33
|
-
console.debug(store.get('username')); // "Mario"
|
|
34
|
-
console.debug(store.get('score')); // 1500
|
|
35
|
-
|
|
36
|
-
// Check if using real persistence
|
|
37
|
-
console.debug(store.isPersistent); // true in browser, false in Node.js/Deno
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### Example 2: Intermediate
|
|
41
|
-
|
|
42
|
-
```javascript
|
|
43
|
-
// Store objects
|
|
44
|
-
store.set('user', { name: 'Luigi', level: 5 });
|
|
45
|
-
const user = store.get('user');
|
|
46
|
-
console.debug(user.name); // "Luigi"
|
|
47
|
-
|
|
48
|
-
// Remove single item
|
|
49
|
-
store.remove('username');
|
|
50
|
-
|
|
51
|
-
// Check size
|
|
52
|
-
const totalSize = store.size();
|
|
53
|
-
console.debug(`${totalSize} bytes`);
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Example 3: Advanced
|
|
57
|
-
|
|
58
|
-
```javascript
|
|
59
|
-
// Get storage quota (returns Promise<[usage, quota]> in KB)
|
|
60
|
-
const [used, total] = await store.quota();
|
|
61
|
-
console.debug(`Using ${used} out of ${total} KB`);
|
|
62
|
-
|
|
63
|
-
// Get total size in characters
|
|
64
|
-
const size = store.size();
|
|
65
|
-
console.debug(`${size} bytes`);
|
|
66
|
-
|
|
67
|
-
// Clear all data
|
|
68
|
-
store.removeAll();
|
|
69
|
-
// or use alias
|
|
70
|
-
store.clearAll();
|
|
71
|
-
|
|
72
|
-
// Handle errors gracefully
|
|
73
|
-
try {
|
|
74
|
-
store.set('largeData', hugeObject);
|
|
75
|
-
} catch (err) {
|
|
76
|
-
console.error('Storage full:', err);
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
|
|
82
|
-
## API Reference
|
|
83
|
-
|
|
84
|
-
### Methods
|
|
85
|
-
|
|
86
|
-
| Method | Parameters | Returns | Description |
|
|
87
|
-
|--------|------------|---------|-------------|
|
|
88
|
-
| `store.get(name)` | `name: string` | `any` | Get value from storage |
|
|
89
|
-
| `store.set(name, value)` | `name: string, value: any` | `void` | Save value to storage |
|
|
90
|
-
| `store.remove(name)` | `name: string` | `boolean` | Remove single item |
|
|
91
|
-
| `store.delete(name)` | `name: string` | `boolean` | Alias for remove |
|
|
92
|
-
| `store.removeAll()` | none | `boolean` | Clear all storage |
|
|
93
|
-
| `store.clearAll()` | none | `boolean` | Alias for removeAll |
|
|
94
|
-
| `store.size()` | none | `number` | Get total size in characters |
|
|
95
|
-
| `store.quota()` | none | `Promise<[number, number]>` | Get storage usage/quota in KB |
|
|
96
|
-
|
|
97
|
-
### Properties
|
|
98
|
-
|
|
99
|
-
| Property | Type | Description |
|
|
100
|
-
|----------|------|-------------|
|
|
101
|
-
| `store.isPersistent` | `boolean` | `true` if using real localStorage, `false` if in-memory fallback |
|
|
102
|
-
|
|
103
|
-
### Supported Types
|
|
104
|
-
|
|
105
|
-
```javascript
|
|
106
|
-
// All JSON-serializable types work
|
|
107
|
-
store.set('string', 'hello');
|
|
108
|
-
store.set('number', 42);
|
|
109
|
-
store.set('boolean', true);
|
|
110
|
-
store.set('array', [1, 2, 3]);
|
|
111
|
-
store.set('object', { key: 'value' });
|
|
112
|
-
store.set('null', null);
|
|
113
|
-
store.set('undefined', null); // converted to null
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Not Supported
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
// Functions will log an error
|
|
120
|
-
store.set('myFunc', () => {});
|
|
121
|
-
// Output: "It's not secure to store functions."
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## Platform Comparison
|
|
127
|
-
|
|
128
|
-
| Feature | Store | Session | Cache | IDB |
|
|
129
|
-
|---------|-------|---------|-------|-----|
|
|
130
|
-
| **Storage** | localStorage | sessionStorage | Memory | IndexedDB |
|
|
131
|
-
| **Lifetime** | Forever | Until tab closes | Until refresh | Forever |
|
|
132
|
-
| **Capacity** | ~5-10 MB | ~5-10 MB | Unlimited | 50+ MB |
|
|
133
|
-
| **Platform** | Browser/Edge | Browser/Edge | All | Browser |
|
|
134
|
-
| **Persistence** | ✅ true | N/A | ❌ false | ✅ true |
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
## How It Works
|
|
139
|
-
|
|
140
|
-
Store wraps the browser's `localStorage` API with:
|
|
141
|
-
|
|
142
|
-
- Automatic JSON serialization/deserialization
|
|
143
|
-
- Error handling for parse failures
|
|
144
|
-
- Size calculation
|
|
145
|
-
- Quota monitoring
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Storage Limits
|
|
150
|
-
|
|
151
|
-
- **Chrome/Safari**: ~5-10 MB
|
|
152
|
-
- **Firefox**: ~10 MB
|
|
153
|
-
- **Edge**: ~5-10 MB
|
|
154
|
-
|
|
155
|
-
Use `store.quota()` to monitor usage.
|
|
156
|
-
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
## Best Practices
|
|
160
|
-
|
|
161
|
-
1. Prefix keys: `store.set('app_username', '...')`
|
|
162
|
-
2. Check before set: `if (store.get('key')) { ... }`
|
|
163
|
-
3. Handle quota: Try/catch around large data
|
|
164
|
-
4. Clean up: `store.removeAll()` on logout
|
package/markdown/TYPED.md
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
# Typed Stores - Memorio
|
|
2
|
-
|
|
3
|
-
> ✅ **Universal**: Works in Browser, Node.js, Deno, and Edge Workers
|
|
4
|
-
|
|
5
|
-
`memorio.typed<T>()` returns the global `state` proxy cast to a TypeScript type `T`, giving you **compile-time** type safety on every access and mutation.
|
|
6
|
-
|
|
7
|
-
It's a **zero-runtime-cost** wrapper: the returned object is the *exact same* Proxy as `globalThis.state`, just with TypeScript types applied via a generic.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
import 'memorio'
|
|
15
|
-
|
|
16
|
-
interface AppState {
|
|
17
|
-
user: { name: string; age: number; email: string }
|
|
18
|
-
theme: 'light' | 'dark'
|
|
19
|
-
items: string[]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const app = memorio.typed<AppState>()
|
|
23
|
-
|
|
24
|
-
// Type-checked at compile time:
|
|
25
|
-
app.user = { name: 'Sara', age: 30, email: 'sara@test.com' }
|
|
26
|
-
app.theme = 'dark'
|
|
27
|
-
|
|
28
|
-
// TypeScript errors:
|
|
29
|
-
// app.user = { name: 42 } // age missing, name wrong type
|
|
30
|
-
// app.theme = 'purple' // not a valid literal
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## Why use typed stores?
|
|
36
|
-
|
|
37
|
-
| Without typed | With `memorio.typed<T>()` |
|
|
38
|
-
|---|---|
|
|
39
|
-
| `state.user = { name: 42 }` — runs silently, bug at runtime | `app.user = { name: 42 }` — TypeScript error at compile time |
|
|
40
|
-
| No autocomplete on `state.user.email` | Full IntelliSense: properties, types, method suggestions |
|
|
41
|
-
| Rename `user` to `profile` — no compiler warning anywhere | Every `app.user` access flagged as an error |
|
|
42
|
-
| AI-generated code lacks guardrails | AI gets autocomplete and type feedback inline |
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Combine with Schema Validation
|
|
47
|
-
|
|
48
|
-
Typed stores catch type errors at compile time; schema validation catches invalid values at runtime. Together they form a **defense-in-depth** strategy:
|
|
49
|
-
|
|
50
|
-
```typescript
|
|
51
|
-
import 'memorio'
|
|
52
|
-
|
|
53
|
-
interface ProfileState {
|
|
54
|
-
profile: { bio: string; avatar?: string }
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const app = memorio.typed<ProfileState>()
|
|
58
|
-
|
|
59
|
-
memorio.registerSchema('profile', {
|
|
60
|
-
type: 'object',
|
|
61
|
-
required: ['bio'],
|
|
62
|
-
properties: {
|
|
63
|
-
bio: { type: 'string', min: 1 },
|
|
64
|
-
avatar: { type: 'string' }
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
app.profile = { bio: 'Developer', avatar: 'pic.png' } // ✅ type + schema pass
|
|
69
|
-
app.profile = { avatar: 'pic.png' } // ❌ TypeScript: bio missing
|
|
70
|
-
// ❌ Runtime: bio required
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
See [Schema Validation](SCHEMA.md) for runtime validation details.
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Named import variant
|
|
78
|
-
|
|
79
|
-
`typed` is also available as a named export if you prefer explicit dependencies:
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
import { typed } from 'memorio'
|
|
83
|
-
|
|
84
|
-
const app = typed<AppState>()
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
The `memorio` namespace object is the same — `import 'memorio'` is the recommended entry, named exports are an alternative.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## Full API
|
|
92
|
-
|
|
93
|
-
| Method | Parameters | Returns | Description |
|
|
94
|
-
|--------|-----------|---------|-------------|
|
|
95
|
-
| `memorio.typed<T>()` | Generic type `T` | `T` | Returns the global `state` proxy cast to `T` |
|
|
96
|
-
|
|
97
|
-
The returned object shares the same identity as `globalThis.state`:
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
const app = memorio.typed<AppState>()
|
|
101
|
-
console.debug(app === state) // true — same Proxy instance
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## React + typed stores
|
|
107
|
-
|
|
108
|
-
Pair with the `useObserver` hook for type-safe, reactive React components:
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
import 'memorio'
|
|
112
|
-
import { useReducer } from 'react'
|
|
113
|
-
|
|
114
|
-
interface AppState {
|
|
115
|
-
user: { name: string; age: number }
|
|
116
|
-
theme: 'light' | 'dark'
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const app = memorio.typed<AppState>()
|
|
120
|
-
|
|
121
|
-
function UserProfile() {
|
|
122
|
-
const [, forceUpdate] = useReducer(x => x + 1, 0)
|
|
123
|
-
|
|
124
|
-
useObserver(forceUpdate, [state.user.name])
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<div>
|
|
128
|
-
<h1>{app.user.name}</h1>
|
|
129
|
-
<span>Theme: {app.theme}</span>
|
|
130
|
-
</div>
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
## Best Practices
|
|
138
|
-
|
|
139
|
-
1. **Define your AppState at the root** of your app and import it everywhere:
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
// types/app-state.ts
|
|
143
|
-
export interface AppState {
|
|
144
|
-
user: { name: string; email: string }
|
|
145
|
-
theme: 'light' | 'dark'
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
// anywhere in your app
|
|
151
|
-
import 'memorio'
|
|
152
|
-
import type { AppState } from '../types/app-state'
|
|
153
|
-
const app = memorio.typed<AppState>()
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
2. **Layer schema validation on top** for runtime safety, especially for data coming from APIs or user input.
|
|
157
|
-
|
|
158
|
-
3. **Use alongside `memorio.help()`** to list available globals during development.
|
package/markdown/USEOBSERVER.md
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
# useObserver - Memorio
|
|
2
|
-
|
|
3
|
-
> ⚛️ **React Only**: This is a React hook and only works within React components
|
|
4
|
-
|
|
5
|
-
useObserver is a React hook for observing state changes. It automatically subscribes to state changes and includes powerful auto-discovery features.
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install memorio
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
```javascript
|
|
14
|
-
import 'memorio';
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## Quick Examples
|
|
20
|
-
|
|
21
|
-
### Example 1: Basic Usage
|
|
22
|
-
|
|
23
|
-
```javascript
|
|
24
|
-
import 'memorio';
|
|
25
|
-
|
|
26
|
-
function Counter() {
|
|
27
|
-
// Direct values work! ✅
|
|
28
|
-
useObserver(() => {
|
|
29
|
-
console.debug('Counter changed:', state.counter);
|
|
30
|
-
}, [state.counter]);
|
|
31
|
-
|
|
32
|
-
return <div>{state.counter}</div>;
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### Auto-Discovery (Magic Mode)
|
|
37
|
-
|
|
38
|
-
```javascript
|
|
39
|
-
// Pass your callback WITHOUT dependencies - it auto-discovers!
|
|
40
|
-
function MyComponent() {
|
|
41
|
-
useObserver(() => {
|
|
42
|
-
// This will automatically track ALL state properties used inside
|
|
43
|
-
console.debug('Something changed:', state.user.name, state.items.length);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
return <div>{state.user.name}</div>;
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Example 2: Intermediate
|
|
51
|
-
|
|
52
|
-
```javascript
|
|
53
|
-
function UserProfile() {
|
|
54
|
-
const [localState, setLocalState] = useState(null);
|
|
55
|
-
|
|
56
|
-
useObserver(() => {
|
|
57
|
-
setLocalState(state.user);
|
|
58
|
-
}, [state.user]);
|
|
59
|
-
|
|
60
|
-
return <div>{localState?.name}</div>;
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Example 3: Advanced
|
|
65
|
-
|
|
66
|
-
```javascript
|
|
67
|
-
// Multiple watchers with array - works with direct values
|
|
68
|
-
function MultiWatch() {
|
|
69
|
-
useObserver(() => {
|
|
70
|
-
console.debug('A or B changed:', state.a, state.b);
|
|
71
|
-
}, [state.a, state.b]); // Direct values work!
|
|
72
|
-
|
|
73
|
-
return <div>{state.a} - {state.b}</div>;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// With string path (for store)
|
|
77
|
-
function StoreWatcher() {
|
|
78
|
-
useObserver(() => {
|
|
79
|
-
console.debug('Store changed');
|
|
80
|
-
}, 'store.userPreferences');
|
|
81
|
-
|
|
82
|
-
return <div />;
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
// With string path (for store)
|
|
86
|
-
function StoreWatcher() {
|
|
87
|
-
useObserver(() => {
|
|
88
|
-
console.debug('Store changed');
|
|
89
|
-
}, 'store.userPreferences');
|
|
90
|
-
|
|
91
|
-
return <div />;
|
|
92
|
-
}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## API Reference
|
|
98
|
-
|
|
99
|
-
### useObserver(callback, deps)
|
|
100
|
-
|
|
101
|
-
| Parameter | Type | Description |
|
|
102
|
-
| --------- | ---- | ----------- |
|
|
103
|
-
| `callback` | `function` | Function to run on change |
|
|
104
|
-
| `deps` | `function \| string \| array \| proxy` | State path(s) to watch. Supports: |
|
|
105
|
-
| | | - Direct values: `state.counter` |
|
|
106
|
-
| | | - String paths: `'state.counter'` |
|
|
107
|
-
| | | - Arrow functions: `() => state.counter` |
|
|
108
|
-
| | | - Arrays: `[state.a, state.b]` or `['state.a', 'state.b']` |
|
|
109
|
-
| | | - Optional chaining: `[state?.one]` |
|
|
110
|
-
|
|
111
|
-
### Primitive Values
|
|
112
|
-
|
|
113
|
-
Direct primitive values are now fully supported:
|
|
114
|
-
|
|
115
|
-
```javascript
|
|
116
|
-
// Direct values work with primitives ✅
|
|
117
|
-
useObserver(() => { console.debug('changed') }, [state.counter])
|
|
118
|
-
|
|
119
|
-
// Arrays of primitives work ✅
|
|
120
|
-
useObserver(() => { console.log(state.a, state.b) }, [state.a, state.b])
|
|
121
|
-
|
|
122
|
-
// Optional chaining works ✅
|
|
123
|
-
useObserver(() => { console.log(state?.one) }, [state?.one])
|
|
124
|
-
|
|
125
|
-
// Strings still work ✅
|
|
126
|
-
useObserver(() => { console.debug('changed') }, ['state.counter'])
|
|
127
|
-
|
|
128
|
-
// Functions still work ✅
|
|
129
|
-
useObserver(() => { console.debug('changed') }, [() => state.counter])
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### Callback Parameters
|
|
133
|
-
|
|
134
|
-
```javascript
|
|
135
|
-
// Single value (no array needed)
|
|
136
|
-
useObserver(
|
|
137
|
-
() => {
|
|
138
|
-
console.debug('Changed:', state.key);
|
|
139
|
-
}, state.key // Single value works!
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
// Array of values
|
|
143
|
-
useObserver(
|
|
144
|
-
() => {
|
|
145
|
-
console.debug('Changed:', state.key);
|
|
146
|
-
}, [state.key] // Array also works!
|
|
147
|
-
);
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### Auto-Discovery Mode
|
|
151
|
-
|
|
152
|
-
When `deps` is omitted, useObserver automatically discovers all state properties accessed inside the callback:
|
|
153
|
-
|
|
154
|
-
```javascript
|
|
155
|
-
// No deps needed - magic auto-discovery!
|
|
156
|
-
useObserver(() => {
|
|
157
|
-
// Automatically tracks state.user, state.items, state.counter
|
|
158
|
-
console.debug(state.user.name, state.items.length, state.counter);
|
|
159
|
-
},[]);
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
Returns a cleanup function:
|
|
163
|
-
|
|
164
|
-
## useObserver vs observer
|
|
165
|
-
|
|
166
|
-
| Feature | observer | useObserver |
|
|
167
|
-
| ------- | -------- | ----------- |
|
|
168
|
-
| Framework | Vanilla JS | React |
|
|
169
|
-
| Auto-cleanup | Manual | Auto |
|
|
170
|
-
| React lifecycle | No | Yes |
|
|
171
|
-
|
|
172
|
-
---
|
|
173
|
-
|
|
174
|
-
## Common Patterns
|
|
175
|
-
|
|
176
|
-
### Sync with useState (Recommended for Primitives)
|
|
177
|
-
|
|
178
|
-
```javascript
|
|
179
|
-
function CounterComponent() {
|
|
180
|
-
// Sync memorio state with React state
|
|
181
|
-
const [counter, setCounter] = useState(state.counter)
|
|
182
|
-
|
|
183
|
-
// React useEffect works correctly with primitive values
|
|
184
|
-
useEffect(() => {
|
|
185
|
-
console.log('Counter changed:', counter)
|
|
186
|
-
}, [counter])
|
|
187
|
-
|
|
188
|
-
// Direct values now work with primitives!
|
|
189
|
-
useObserver(() => {
|
|
190
|
-
setCounter(state.counter)
|
|
191
|
-
}, [state.counter]) // ✅ Works now!
|
|
192
|
-
|
|
193
|
-
return (
|
|
194
|
-
<div>
|
|
195
|
-
<button onClick={() => { state.counter++ }}>Increment</button>
|
|
196
|
-
<span>{counter}</span>
|
|
197
|
-
</div>
|
|
198
|
-
)
|
|
199
|
-
}
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Safe Access with Optional Chaining (Protection)
|
|
203
|
-
|
|
204
|
-
```javascript
|
|
205
|
-
// Optional chaining is supported - protects against errors
|
|
206
|
-
useObserver(() => {
|
|
207
|
-
if (test?.one) {
|
|
208
|
-
console.log(test.one)
|
|
209
|
-
}
|
|
210
|
-
}, [test?.one])
|
|
211
|
-
|
|
212
|
-
// Works with objects
|
|
213
|
-
function SafeComponent() {
|
|
214
|
-
const [test, setTest] = useState(state.test)
|
|
215
|
-
|
|
216
|
-
useEffect(() => {
|
|
217
|
-
if (test?.one) {
|
|
218
|
-
console.log('test.one:', test.one)
|
|
219
|
-
}
|
|
220
|
-
}, [test?.one])
|
|
221
|
-
|
|
222
|
-
useObserver(() => {
|
|
223
|
-
if (state.test?.one) {
|
|
224
|
-
setTest(state.test)
|
|
225
|
-
}
|
|
226
|
-
}, ['state.test.one'])
|
|
227
|
-
|
|
228
|
-
return <div>{test?.one || 'Loading...'}</div>
|
|
229
|
-
}
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Multiple Watchers
|
|
233
|
-
|
|
234
|
-
```javascript
|
|
235
|
-
// Watch multiple properties with strings
|
|
236
|
-
useObserver(() => {
|
|
237
|
-
console.log(state.a, state.b)
|
|
238
|
-
}, ['state.a', 'state.b'])
|
|
239
|
-
|
|
240
|
-
// Watch multiple properties with functions
|
|
241
|
-
useObserver(() => {
|
|
242
|
-
console.log(state.a, state.b)
|
|
243
|
-
}, [() => state.a, () => state.b])
|
|
244
|
-
|
|
245
|
-
// Watch with auto-discovery
|
|
246
|
-
useObserver(() => {
|
|
247
|
-
console.log(state.a, state.b) // Automatically tracks both
|
|
248
|
-
}, [])
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
## Best Practices
|
|
254
|
-
|
|
255
|
-
1. Always use in React components
|
|
256
|
-
2. Use auto-discovery for simpler code: `useObserver(() => { ... })`
|
|
257
|
-
3. No manual cleanup needed - returns cleanup function automatically
|
|
258
|
-
4. Use with state for reactive UI
|
|
259
|
-
5. Check console for auto-discovery logs
|