r-state-tree 0.8.0 → 0.8.1
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 +8 -4
- package/dist/r-state-tree.cjs +49 -22
- package/dist/r-state-tree.js +49 -22
- package/dist/store/StoreAdministration.d.ts +4 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ app.todo.title;
|
|
|
139
139
|
|
|
140
140
|
- Always create with `createStore()` and attach with `mount()`. Stores cannot be constructed with `new` directly.
|
|
141
141
|
- Prefer no custom constructor. Type stores as `Store<Props>` and access props via `this.props`.
|
|
142
|
-
- Constructors may register framework-owned reactions and effects after `super(props)`.
|
|
142
|
+
- Constructors may register framework-owned reactions and effects after `super(props)`. Store registrations activate when mounting and are disposed with the store; return cleanup from effects to release resources.
|
|
143
143
|
- Do not shadow or re-declare `props` as a class field; `props` is read-only. Use the generic `Store<{ ... }>` for typing.
|
|
144
144
|
|
|
145
145
|
```ts
|
|
@@ -212,7 +212,6 @@ class TodoStore extends Store {
|
|
|
212
212
|
constructor(props) {
|
|
213
213
|
super(props);
|
|
214
214
|
this.effect(() => {
|
|
215
|
-
if (!this.isMounted) return;
|
|
216
215
|
const connection = connect();
|
|
217
216
|
return () => connection.close();
|
|
218
217
|
});
|
|
@@ -243,6 +242,10 @@ class TodoStore extends Store {
|
|
|
243
242
|
}
|
|
244
243
|
```
|
|
245
244
|
|
|
245
|
+
`Store.effect()` and `Store.reaction()` register mount-scoped behavior. Mounting first links the complete store tree and marks it mounted bottom-up in one transaction. Registrations then activate bottom-up, so even a grandchild's initial effect observes every ancestor and descendant as mounted. A reaction establishes its initial value at activation and still skips its initial callback. Calling the disposer returned during construction cancels the pending registration; after mount, it disposes the live subscription. All registrations are disposed automatically with the store.
|
|
246
|
+
|
|
247
|
+
Use the exported standalone `effect()` or `reaction()` when observing a store from outside its owned lifetime—for example, to observe the public reactive `isMounted` transition to `false`.
|
|
248
|
+
|
|
246
249
|
### Context
|
|
247
250
|
|
|
248
251
|
Share data across the store tree without prop drilling:
|
|
@@ -1217,7 +1220,8 @@ class S extends Store {
|
|
|
1217
1220
|
constructor(props) {
|
|
1218
1221
|
super(props);
|
|
1219
1222
|
this.effect(() => {
|
|
1220
|
-
|
|
1223
|
+
const resource = acquireResource();
|
|
1224
|
+
return () => resource.dispose();
|
|
1221
1225
|
});
|
|
1222
1226
|
}
|
|
1223
1227
|
}
|
|
@@ -1281,7 +1285,7 @@ When child stores are created during mount with `models` that point back into th
|
|
|
1281
1285
|
- Core: `createStore`, `mount`, `Symbol.dispose`, `updateStore`
|
|
1282
1286
|
- Snapshots: `onSnapshot`, `toSnapshot`, `applySnapshot`, `onSnapshotDiff`
|
|
1283
1287
|
- Lifecycle: reactive `Store.isMounted`, reactive `Model.parent`, and owned `reaction`/`effect`
|
|
1284
|
-
- Best practices: domain in Models; delegate from Stores; stable keys for `@child`;
|
|
1288
|
+
- Best practices: domain in Models; delegate from Stores; stable keys for `@child`; return cleanup from store effects; don’t shadow `props`.
|
|
1285
1289
|
|
|
1286
1290
|
## Testing
|
|
1287
1291
|
|
package/dist/r-state-tree.cjs
CHANGED
|
@@ -2036,7 +2036,7 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2036
2036
|
disposed = false;
|
|
2037
2037
|
contextCache = /* @__PURE__ */ new Map();
|
|
2038
2038
|
childStoreDataMap = /* @__PURE__ */ new Map();
|
|
2039
|
-
|
|
2039
|
+
reactiveRegistrations = /* @__PURE__ */ new Set();
|
|
2040
2040
|
configurationGetter;
|
|
2041
2041
|
setConfiguration(configurationGetter) {
|
|
2042
2042
|
this.configurationGetter = configurationGetter;
|
|
@@ -2060,7 +2060,9 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2060
2060
|
}
|
|
2061
2061
|
});
|
|
2062
2062
|
childStoreData.value.set(stores);
|
|
2063
|
-
|
|
2063
|
+
if (this.isMounted) {
|
|
2064
|
+
stores.forEach((s) => getStoreAdm(s).mount(this, name));
|
|
2065
|
+
}
|
|
2064
2066
|
return stores;
|
|
2065
2067
|
}
|
|
2066
2068
|
const newStores = /* @__PURE__ */ new Set();
|
|
@@ -2111,7 +2113,9 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2111
2113
|
signalsCore.batch(() => childStoreData.value.set(stores));
|
|
2112
2114
|
}
|
|
2113
2115
|
removedStores.forEach((s) => getStoreAdm(s).dispose(true));
|
|
2114
|
-
|
|
2116
|
+
if (this.isMounted) {
|
|
2117
|
+
newStores.forEach((s) => getStoreAdm(s).mount(this, name));
|
|
2118
|
+
}
|
|
2115
2119
|
return stores;
|
|
2116
2120
|
}
|
|
2117
2121
|
setSingleStore(name, element) {
|
|
@@ -2130,7 +2134,9 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2130
2134
|
}
|
|
2131
2135
|
const childStore = this.createChildStore(element);
|
|
2132
2136
|
signalsCore.batch(() => childStoreData.value.set(childStore));
|
|
2133
|
-
|
|
2137
|
+
if (this.isMounted) {
|
|
2138
|
+
getStoreAdm(childStore).mount(this, name);
|
|
2139
|
+
}
|
|
2134
2140
|
return childStore;
|
|
2135
2141
|
} else {
|
|
2136
2142
|
signalsCore.batch(() => updateProps(oldStore.props, props));
|
|
@@ -2223,31 +2229,37 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2223
2229
|
}
|
|
2224
2230
|
return void 0;
|
|
2225
2231
|
}
|
|
2226
|
-
|
|
2232
|
+
register(start) {
|
|
2227
2233
|
if (this.disposed) {
|
|
2228
|
-
disposer();
|
|
2229
2234
|
throw new Error(
|
|
2230
2235
|
"r-state-tree: cannot register reactive resources on a disposed store"
|
|
2231
2236
|
);
|
|
2232
2237
|
}
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2238
|
+
const registration = { start, disposed: false };
|
|
2239
|
+
this.reactiveRegistrations.add(registration);
|
|
2240
|
+
if (this.isMounted) registration.stop = registration.start();
|
|
2241
|
+
return () => {
|
|
2242
|
+
if (registration.disposed) return;
|
|
2243
|
+
registration.disposed = true;
|
|
2244
|
+
this.reactiveRegistrations.delete(registration);
|
|
2245
|
+
registration.stop?.();
|
|
2246
|
+
registration.stop = void 0;
|
|
2239
2247
|
};
|
|
2240
|
-
|
|
2241
|
-
|
|
2248
|
+
}
|
|
2249
|
+
startReactiveRegistrations() {
|
|
2250
|
+
this.reactiveRegistrations.forEach((registration) => {
|
|
2251
|
+
if (!registration.disposed && !registration.stop) {
|
|
2252
|
+
registration.stop = registration.start();
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2242
2255
|
}
|
|
2243
2256
|
reaction(track, callback) {
|
|
2244
|
-
|
|
2245
|
-
return this.own(unsub);
|
|
2257
|
+
return this.register(() => reaction(track, callback));
|
|
2246
2258
|
}
|
|
2247
2259
|
effect(callback) {
|
|
2248
|
-
return this.
|
|
2260
|
+
return this.register(() => signalsCore.effect(callback));
|
|
2249
2261
|
}
|
|
2250
|
-
mount(parent = null, childName) {
|
|
2262
|
+
mount(parent = null, childName, activationQueue) {
|
|
2251
2263
|
if (this.disposed) {
|
|
2252
2264
|
throw new Error("r-state-tree: cannot mount a disposed store");
|
|
2253
2265
|
}
|
|
@@ -2263,19 +2275,29 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2263
2275
|
throw createCircularMountError(frame);
|
|
2264
2276
|
}
|
|
2265
2277
|
mountingStack.push(frame);
|
|
2278
|
+
const isOutermostMount = activationQueue === void 0;
|
|
2279
|
+
const registrationsToStart = activationQueue ?? [];
|
|
2266
2280
|
try {
|
|
2267
2281
|
signalsCore.batch(() => {
|
|
2268
2282
|
this.parent = parent || null;
|
|
2269
2283
|
this.childStoreDataMap.forEach(({ value }, name) => {
|
|
2270
2284
|
const stores = value.get();
|
|
2271
2285
|
if (Array.isArray(stores)) {
|
|
2272
|
-
stores?.forEach(
|
|
2286
|
+
stores?.forEach(
|
|
2287
|
+
(s) => getStoreAdm(s)?.mount(this, name, registrationsToStart)
|
|
2288
|
+
);
|
|
2273
2289
|
} else if (stores) {
|
|
2274
|
-
getStoreAdm(stores)?.mount(this, name);
|
|
2290
|
+
getStoreAdm(stores)?.mount(this, name, registrationsToStart);
|
|
2275
2291
|
}
|
|
2276
2292
|
});
|
|
2277
2293
|
this.mountedSignal.set(true);
|
|
2294
|
+
registrationsToStart.push(this);
|
|
2278
2295
|
});
|
|
2296
|
+
if (isOutermostMount) {
|
|
2297
|
+
registrationsToStart.forEach(
|
|
2298
|
+
(store) => store.startReactiveRegistrations()
|
|
2299
|
+
);
|
|
2300
|
+
}
|
|
2279
2301
|
} catch (error) {
|
|
2280
2302
|
if (error instanceof Error && (error instanceof RangeError && /call stack/i.test(error.message) || /cycle detected/i.test(error.message))) {
|
|
2281
2303
|
throw createCircularMountError(frame);
|
|
@@ -2307,9 +2329,14 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2307
2329
|
this.contextCache.clear();
|
|
2308
2330
|
this.parent = null;
|
|
2309
2331
|
});
|
|
2310
|
-
this.mountedSignal.set(false);
|
|
2311
2332
|
this.disposed = true;
|
|
2312
|
-
|
|
2333
|
+
this.reactiveRegistrations.forEach((registration) => {
|
|
2334
|
+
registration.disposed = true;
|
|
2335
|
+
registration.stop?.();
|
|
2336
|
+
registration.stop = void 0;
|
|
2337
|
+
});
|
|
2338
|
+
this.reactiveRegistrations.clear();
|
|
2339
|
+
this.mountedSignal.set(false);
|
|
2313
2340
|
}
|
|
2314
2341
|
}
|
|
2315
2342
|
let initEnabled$1 = false;
|
package/dist/r-state-tree.js
CHANGED
|
@@ -2035,7 +2035,7 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2035
2035
|
disposed = false;
|
|
2036
2036
|
contextCache = /* @__PURE__ */ new Map();
|
|
2037
2037
|
childStoreDataMap = /* @__PURE__ */ new Map();
|
|
2038
|
-
|
|
2038
|
+
reactiveRegistrations = /* @__PURE__ */ new Set();
|
|
2039
2039
|
configurationGetter;
|
|
2040
2040
|
setConfiguration(configurationGetter) {
|
|
2041
2041
|
this.configurationGetter = configurationGetter;
|
|
@@ -2059,7 +2059,9 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2059
2059
|
}
|
|
2060
2060
|
});
|
|
2061
2061
|
childStoreData.value.set(stores);
|
|
2062
|
-
|
|
2062
|
+
if (this.isMounted) {
|
|
2063
|
+
stores.forEach((s) => getStoreAdm(s).mount(this, name));
|
|
2064
|
+
}
|
|
2063
2065
|
return stores;
|
|
2064
2066
|
}
|
|
2065
2067
|
const newStores = /* @__PURE__ */ new Set();
|
|
@@ -2110,7 +2112,9 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2110
2112
|
batch(() => childStoreData.value.set(stores));
|
|
2111
2113
|
}
|
|
2112
2114
|
removedStores.forEach((s) => getStoreAdm(s).dispose(true));
|
|
2113
|
-
|
|
2115
|
+
if (this.isMounted) {
|
|
2116
|
+
newStores.forEach((s) => getStoreAdm(s).mount(this, name));
|
|
2117
|
+
}
|
|
2114
2118
|
return stores;
|
|
2115
2119
|
}
|
|
2116
2120
|
setSingleStore(name, element) {
|
|
@@ -2129,7 +2133,9 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2129
2133
|
}
|
|
2130
2134
|
const childStore = this.createChildStore(element);
|
|
2131
2135
|
batch(() => childStoreData.value.set(childStore));
|
|
2132
|
-
|
|
2136
|
+
if (this.isMounted) {
|
|
2137
|
+
getStoreAdm(childStore).mount(this, name);
|
|
2138
|
+
}
|
|
2133
2139
|
return childStore;
|
|
2134
2140
|
} else {
|
|
2135
2141
|
batch(() => updateProps(oldStore.props, props));
|
|
@@ -2222,31 +2228,37 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2222
2228
|
}
|
|
2223
2229
|
return void 0;
|
|
2224
2230
|
}
|
|
2225
|
-
|
|
2231
|
+
register(start) {
|
|
2226
2232
|
if (this.disposed) {
|
|
2227
|
-
disposer();
|
|
2228
2233
|
throw new Error(
|
|
2229
2234
|
"r-state-tree: cannot register reactive resources on a disposed store"
|
|
2230
2235
|
);
|
|
2231
2236
|
}
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2237
|
+
const registration = { start, disposed: false };
|
|
2238
|
+
this.reactiveRegistrations.add(registration);
|
|
2239
|
+
if (this.isMounted) registration.stop = registration.start();
|
|
2240
|
+
return () => {
|
|
2241
|
+
if (registration.disposed) return;
|
|
2242
|
+
registration.disposed = true;
|
|
2243
|
+
this.reactiveRegistrations.delete(registration);
|
|
2244
|
+
registration.stop?.();
|
|
2245
|
+
registration.stop = void 0;
|
|
2238
2246
|
};
|
|
2239
|
-
|
|
2240
|
-
|
|
2247
|
+
}
|
|
2248
|
+
startReactiveRegistrations() {
|
|
2249
|
+
this.reactiveRegistrations.forEach((registration) => {
|
|
2250
|
+
if (!registration.disposed && !registration.stop) {
|
|
2251
|
+
registration.stop = registration.start();
|
|
2252
|
+
}
|
|
2253
|
+
});
|
|
2241
2254
|
}
|
|
2242
2255
|
reaction(track, callback) {
|
|
2243
|
-
|
|
2244
|
-
return this.own(unsub);
|
|
2256
|
+
return this.register(() => reaction(track, callback));
|
|
2245
2257
|
}
|
|
2246
2258
|
effect(callback) {
|
|
2247
|
-
return this.
|
|
2259
|
+
return this.register(() => effect(callback));
|
|
2248
2260
|
}
|
|
2249
|
-
mount(parent = null, childName) {
|
|
2261
|
+
mount(parent = null, childName, activationQueue) {
|
|
2250
2262
|
if (this.disposed) {
|
|
2251
2263
|
throw new Error("r-state-tree: cannot mount a disposed store");
|
|
2252
2264
|
}
|
|
@@ -2262,19 +2274,29 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2262
2274
|
throw createCircularMountError(frame);
|
|
2263
2275
|
}
|
|
2264
2276
|
mountingStack.push(frame);
|
|
2277
|
+
const isOutermostMount = activationQueue === void 0;
|
|
2278
|
+
const registrationsToStart = activationQueue ?? [];
|
|
2265
2279
|
try {
|
|
2266
2280
|
batch(() => {
|
|
2267
2281
|
this.parent = parent || null;
|
|
2268
2282
|
this.childStoreDataMap.forEach(({ value }, name) => {
|
|
2269
2283
|
const stores = value.get();
|
|
2270
2284
|
if (Array.isArray(stores)) {
|
|
2271
|
-
stores?.forEach(
|
|
2285
|
+
stores?.forEach(
|
|
2286
|
+
(s) => getStoreAdm(s)?.mount(this, name, registrationsToStart)
|
|
2287
|
+
);
|
|
2272
2288
|
} else if (stores) {
|
|
2273
|
-
getStoreAdm(stores)?.mount(this, name);
|
|
2289
|
+
getStoreAdm(stores)?.mount(this, name, registrationsToStart);
|
|
2274
2290
|
}
|
|
2275
2291
|
});
|
|
2276
2292
|
this.mountedSignal.set(true);
|
|
2293
|
+
registrationsToStart.push(this);
|
|
2277
2294
|
});
|
|
2295
|
+
if (isOutermostMount) {
|
|
2296
|
+
registrationsToStart.forEach(
|
|
2297
|
+
(store) => store.startReactiveRegistrations()
|
|
2298
|
+
);
|
|
2299
|
+
}
|
|
2278
2300
|
} catch (error) {
|
|
2279
2301
|
if (error instanceof Error && (error instanceof RangeError && /call stack/i.test(error.message) || /cycle detected/i.test(error.message))) {
|
|
2280
2302
|
throw createCircularMountError(frame);
|
|
@@ -2306,9 +2328,14 @@ class StoreAdministration extends PreactObjectAdministration {
|
|
|
2306
2328
|
this.contextCache.clear();
|
|
2307
2329
|
this.parent = null;
|
|
2308
2330
|
});
|
|
2309
|
-
this.mountedSignal.set(false);
|
|
2310
2331
|
this.disposed = true;
|
|
2311
|
-
|
|
2332
|
+
this.reactiveRegistrations.forEach((registration) => {
|
|
2333
|
+
registration.disposed = true;
|
|
2334
|
+
registration.stop?.();
|
|
2335
|
+
registration.stop = void 0;
|
|
2336
|
+
});
|
|
2337
|
+
this.reactiveRegistrations.clear();
|
|
2338
|
+
this.mountedSignal.set(false);
|
|
2312
2339
|
}
|
|
2313
2340
|
}
|
|
2314
2341
|
let initEnabled$1 = false;
|
|
@@ -10,7 +10,7 @@ export declare class StoreAdministration<StoreType extends Store = Store> extend
|
|
|
10
10
|
private disposed;
|
|
11
11
|
private contextCache;
|
|
12
12
|
private childStoreDataMap;
|
|
13
|
-
private
|
|
13
|
+
private reactiveRegistrations;
|
|
14
14
|
private configurationGetter?;
|
|
15
15
|
setConfiguration(configurationGetter: () => StoreConfiguration<StoreType>): void;
|
|
16
16
|
private get configuration();
|
|
@@ -26,9 +26,10 @@ export declare class StoreAdministration<StoreType extends Store = Store> extend
|
|
|
26
26
|
get isMounted(): boolean;
|
|
27
27
|
getContextValue<T>(contextId: symbol, provideSymbol: symbol, defaultValue: T | undefined, hasDefault: boolean): T;
|
|
28
28
|
private lookupContextValue;
|
|
29
|
-
private
|
|
29
|
+
private register;
|
|
30
|
+
private startReactiveRegistrations;
|
|
30
31
|
reaction<T>(track: () => T, callback: (value: T, previousValue: T) => void): () => void;
|
|
31
32
|
effect(callback: () => void | (() => void)): () => void;
|
|
32
|
-
mount(parent?: StoreAdministration | null, childName?: PropertyKey): void;
|
|
33
|
+
mount(parent?: StoreAdministration | null, childName?: PropertyKey, activationQueue?: StoreAdministration[]): void;
|
|
33
34
|
dispose(internal?: boolean): void;
|
|
34
35
|
}
|