@xmachines/play-react 1.0.0-beta.53 → 1.0.0-beta.54

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
@@ -108,7 +108,7 @@ function MyComponent({ actor }) {
108
108
 
109
109
  useSignalEffect(() => {
110
110
  setView(actor.currentView.get());
111
- });
111
+ }, [actor]); // deps: re-subscribe when the actor prop swaps
112
112
 
113
113
  return <div>{view?.component}</div>;
114
114
  }
@@ -127,11 +127,11 @@ function MyComponent({ actor }) {
127
127
 
128
128
  ### Hooks
129
129
 
130
- | Export | Description |
131
- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
132
- | `useSignalEffect(callback)` | Subscribes to TC39 signal changes; re-runs the callback and forces a React re-render when any accessed signal changes. Cleanup is automatic on unmount. |
133
- | `useActor()` | Returns the raw actor instance. Must be called inside an `ActorProvider`/`PlayUIProvider` tree. |
134
- | `usePlayView()` | Returns `{ spec, handlers, registry, store }` for the current view. Must be called inside an `ActorProvider`/`PlayUIProvider` tree. |
130
+ | Export | Description |
131
+ | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
132
+ | `useSignalEffect(callback, deps?)` | Subscribes to TC39 signal changes; re-runs the callback when any accessed signal changes (re-render via the callback's own setState). Optional `deps` recreates the subscription, like `useEffect`. Cleanup is automatic on unmount. |
133
+ | `useActor()` | Returns the raw actor instance. Must be called inside an `ActorProvider`/`PlayUIProvider` tree. |
134
+ | `usePlayView()` | Returns `{ spec, handlers, registry, store }` for the current view. Must be called inside an `ActorProvider`/`PlayUIProvider` tree. |
135
135
 
136
136
  ### Types
137
137
 
@@ -11,7 +11,7 @@
11
11
  */
12
12
  import React from "react";
13
13
  import type { DefineRegistryResult, ComponentRegistry } from "@json-render/react";
14
- import type { BaseActorProviderProps, BaseViewContextValue } from "@xmachines/play-actor";
14
+ import { type BaseActorProviderProps, type BaseViewContextValue } from "@xmachines/play-actor";
15
15
  /**
16
16
  * Props for the ActorProvider component.
17
17
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ActorProvider.d.ts","sourceRoot":"","sources":["../src/ActorProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAA+D,MAAM,OAAO,CAAC;AAEpF,OAAO,KAAK,EAAE,oBAAoB,EAAY,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5F,OAAO,KAAK,EAAY,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAIpG;;;;GAIG;AACH,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB,CAAC,oBAAoB,CAAC;IACvF,sFAAsF;IACtF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,4FAA4F;IAC5F,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC;IACxD,0DAA0D;IAC1D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;CAAG;AAQpF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,IAAI,gBAAgB,CAE9C;AAoED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA0FtD,CAAC"}
1
+ {"version":3,"file":"ActorProvider.d.ts","sourceRoot":"","sources":["../src/ActorProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAA+D,MAAM,OAAO,CAAC;AAEpF,OAAO,KAAK,EAAE,oBAAoB,EAAY,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5F,OAAO,EAIN,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,MAAM,uBAAuB,CAAC;AAI/B;;;;GAIG;AACH,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB,CAAC,oBAAoB,CAAC;IACvF,sFAAsF;IACtF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,4FAA4F;IAC5F,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC;IACxD,0DAA0D;IAC1D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;CAAG;AAQpF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,IAAI,gBAAgB,CAE9C;AA0ED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAqFtD,CAAC"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  /**
3
3
  * ActorProvider — escape hatch primitive for actor lifecycle management.
4
4
  *
@@ -17,6 +17,7 @@ import { xstateStoreStateStore } from "@json-render/xstate";
17
17
  import { useSignalEffect } from "./useSignalEffect.js";
18
18
  import { PlayErrorBoundary } from "./PlayErrorBoundary.js";
19
19
  import { assertNonNullable } from "@xmachines/play";
20
+ import { toAtomState, attachRenderErrorHandler, } from "@xmachines/play-actor";
20
21
  import { ActorContext } from "./useActor.js";
21
22
  /**
22
23
  * Internal React context for ViewContextValue.
@@ -79,12 +80,15 @@ function ActorProviderInner({ registryResult, spec, store, children, }) {
79
80
  // recreated when the registry definition itself changes (e.g. a new defineRegistry
80
81
  // call), not on every render cycle.
81
82
  const handlers = useMemo(() => registryResult.handlers(() => setStateAdapterRef.current, () => stateCtxRef.current.getSnapshot()), [registryResult]);
82
- const viewValue = {
83
+ // Memoize the context value on its actual inputs — a fresh object every
84
+ // render would re-render every usePlayView() consumer even when nothing
85
+ // changed (wasted renders).
86
+ const viewValue = useMemo(() => ({
83
87
  spec,
84
88
  handlers,
85
89
  registry: registryResult.registry,
86
90
  store,
87
- };
91
+ }), [spec, handlers, registryResult.registry, store]);
88
92
  return _jsx(ViewContext.Provider, { value: viewValue, children: children });
89
93
  }
90
94
  /**
@@ -122,30 +126,34 @@ export const ActorProvider = ({ actor, registryResult, store: externalStore, fal
122
126
  // Ignored when externalStore is provided.
123
127
  const internalStoreRef = useRef(null);
124
128
  const lastViewRef = useRef(null);
125
- // Subscribe to signal changes
129
+ // Subscribe to signal changes. The [actor] dep re-creates the watcher when
130
+ // the actor prop swaps — without it the watcher keeps tracking the OLD
131
+ // actor's currentView signal and the rendered view freezes on the old actor
132
+ // while events flow to the new one.
126
133
  useSignalEffect(() => {
127
134
  const currentView = actor.currentView.get();
128
135
  setView(currentView);
129
- });
136
+ }, [actor]);
130
137
  // Inject onRenderError prop into registry (non-enumerable, overrides defineRegistry-level handler)
131
- // Centralised here per D-19 — one location for all framework renderers
132
- const activeRegistryResult = onRenderError
133
- ? {
138
+ // Centralised here per D-19 — one location for all framework renderers.
139
+ // Memoized on its actual inputs: rebuilding the injected registry every render
140
+ // would churn registry identity and invalidate ActorProviderInner's handlers
141
+ // useMemo on every render (wasted work + wasted consumer re-renders).
142
+ const activeRegistryResult = useMemo(() => {
143
+ if (!onRenderError)
144
+ return registryResult;
145
+ return {
134
146
  ...registryResult,
135
- registry: (() => {
136
- const r = { ...registryResult.registry };
137
- Object.defineProperty(r, "onRenderError", {
138
- value: onRenderError,
139
- enumerable: false,
140
- configurable: true,
141
- });
142
- return r;
143
- })(),
144
- }
145
- : registryResult;
146
- // No view in current state — render fallback
147
+ registry: attachRenderErrorHandler(registryResult.registry, onRenderError),
148
+ };
149
+ }, [registryResult, onRenderError]);
150
+ // No view in current state — render fallback INSIDE ActorContext so a
151
+ // fallback component can call useActor() (e.g. to send a retry event).
152
+ // Parity with the error-boundary fallback below and with the Solid/Svelte/Vue
153
+ // renderers, which all provide context to their null-view fallbacks.
154
+ // ViewContext is intentionally NOT provided: there is no view spec to expose.
147
155
  if (!view) {
148
- return _jsx(_Fragment, { children: fallback });
156
+ return (_jsx(ActorContext.Provider, { value: actor, children: fallback }));
149
157
  }
150
158
  // Resolve the store to use for StateProvider:
151
159
  // - External (controlled): use as-is, caller manages lifecycle
@@ -160,16 +168,7 @@ export const ActorProvider = ({ actor, registryResult, store: externalStore, fal
160
168
  if (internalStoreRef.current === null || lastViewRef.current !== view) {
161
169
  // Proto-safe guard (T-37-03-01): prevents Date/Array/class-instance from being
162
170
  // passed to createAtom. Replaces the weak `?? {}` guard from old code_context.
163
- const rawState = view.state;
164
- const initialState = rawState !== null &&
165
- rawState !== undefined &&
166
- typeof rawState === "object" &&
167
- !Array.isArray(rawState) &&
168
- (Object.getPrototypeOf(rawState) === Object.prototype ||
169
- Object.getPrototypeOf(rawState) === null)
170
- ? rawState
171
- : {};
172
- internalStoreRef.current = createViewStore(initialState);
171
+ internalStoreRef.current = createViewStore(toAtomState(view.state));
173
172
  lastViewRef.current = view;
174
173
  }
175
174
  store = internalStoreRef.current;
@@ -1 +1 @@
1
- {"version":3,"file":"ActorProvider.js","sourceRoot":"","sources":["../src/ActorProvider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ActorProvider.js","sourceRoot":"","sources":["../src/ActorProvider.tsx"],"names":[],"mappings":"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"}
package/dist/errors.d.ts CHANGED
@@ -7,7 +7,7 @@ import { PlayError } from "@xmachines/play";
7
7
  * root. `RendererError` is retained for programmatic use in custom error handlers
8
8
  * and parent boundaries — it is no longer emitted by the built-in boundary itself.
9
9
  *
10
- * **Error code:** `PLAY_RENDERER_RENDER_ERROR`
10
+ * **Error code:** `PLAY_REACT_RENDER_ERROR`
11
11
  *
12
12
  * @example
13
13
  * ```typescript
package/dist/errors.js CHANGED
@@ -7,7 +7,7 @@ import { PlayError } from "@xmachines/play";
7
7
  * root. `RendererError` is retained for programmatic use in custom error handlers
8
8
  * and parent boundaries — it is no longer emitted by the built-in boundary itself.
9
9
  *
10
- * **Error code:** `PLAY_RENDERER_RENDER_ERROR`
10
+ * **Error code:** `PLAY_REACT_RENDER_ERROR`
11
11
  *
12
12
  * @example
13
13
  * ```typescript
@@ -19,7 +19,7 @@ import { PlayError } from "@xmachines/play";
19
19
  */
20
20
  export class RendererError extends PlayError {
21
21
  constructor(message, options) {
22
- super("PlayRenderer", "PLAY_RENDERER_RENDER_ERROR", message, options);
22
+ super("PlayRenderer", "PLAY_REACT_RENDER_ERROR", message, options);
23
23
  this.name = "RendererError";
24
24
  }
25
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,aAAc,SAAQ,SAAS;IAC3C,YAAY,OAAe,EAAE,OAAsB;QAClD,KAAK,CAAC,cAAc,EAAE,4BAA4B,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC7B,CAAC;CACD"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,aAAc,SAAQ,SAAS;IAC3C,YAAY,OAAe,EAAE,OAAsB;QAClD,KAAK,CAAC,cAAc,EAAE,yBAAyB,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACnE,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC7B,CAAC;CACD"}
@@ -3,35 +3,44 @@
3
3
  *
4
4
  * @packageDocumentation
5
5
  */
6
+ import type { DependencyList } from "react";
6
7
  /**
7
8
  * React hook that subscribes to signal changes and runs effect callback
8
9
  *
9
- * Wraps Signal.subtle.Watcher to automatically track signal dependencies
10
- * accessed in the callback. When any tracked signal changes, the callback
11
- * re-runs and React component re-renders.
10
+ * Wraps the callback in a Signal.Computed to automatically track signal
11
+ * dependencies accessed inside it, then delegates the watcher lifecycle
12
+ * (microtask batching, re-arming, disposal) to `watchSignal` from
13
+ * `@xmachines/play-signals` — the single canonical implementation shared
14
+ * across framework renderers.
12
15
  *
13
- * Architecture (per RESEARCH.md Pattern 3):
16
+ * Architecture:
14
17
  * - Uses Signal.Computed to wrap callback for automatic dependency tracking
15
- * - Signal.subtle.Watcher monitors the Computed for changes
18
+ * - watchSignal owns the Signal.subtle.Watcher lifecycle (Phase 29 memory safety)
16
19
  * - Microtask batching coalesces rapid signal updates
17
- * - Forces React re-render via useReducer when signals change
20
+ * - Re-rendering is driven by the callback's own setState (see remarks)
18
21
  * - Handles cleanup on unmount to prevent memory leaks
19
22
  *
20
23
  * Invariant: Signal-Only Reactivity - Signals accessed in callback are watched.
21
24
  * Invariant: Passive Infrastructure - React observes signals and does not control them.
22
25
  *
23
26
  * @param callback - Effect function that accesses signals. Can return cleanup function.
27
+ * @param deps - Optional dependency list (like useEffect). When any dependency
28
+ * changes, the watcher and Computed are torn down and recreated, re-tracking
29
+ * signals from scratch. Defaults to `[]` (subscribe once per mount). Pass this
30
+ * when the identity of the object whose signals you read can change over the
31
+ * component's lifetime (e.g. an `actor` prop) — otherwise the watcher keeps
32
+ * tracking the OLD object's signals forever.
24
33
  *
25
34
  * @example
26
35
  * ```typescript
27
36
  * const MyComponent = ({ actor }) => {
28
37
  * const [view, setView] = useState(null);
29
38
  *
30
- * // Subscribe to actor.currentView signal
39
+ * // Subscribe to actor.currentView signal; re-subscribe if the actor swaps
31
40
  * useSignalEffect(() => {
32
41
  * const currentView = actor.currentView.get();
33
42
  * setView(currentView);
34
- * });
43
+ * }, [actor]);
35
44
  *
36
45
  * return <div>{view?.component}</div>;
37
46
  * };
@@ -41,22 +50,22 @@
41
50
  * **CRITICAL:** Signals must be accessed unconditionally (no if statements).
42
51
  * Conditional signal access breaks automatic dependency tracking.
43
52
  *
44
- * **Performance:** Microtask batching (queueMicrotask) prevents React thrashing
45
- * when multiple signals update rapidly. Per signal-polyfill README pattern.
53
+ * **Performance:** Microtask batching (queueMicrotask, inside watchSignal)
54
+ * prevents React thrashing when multiple signals update rapidly.
46
55
  *
47
- * **Why forceUpdate:** React needs useState/useReducer to trigger re-render cycle.
48
- * Signal changes won't automatically re-render React components without forcing
49
- * update via state change.
56
+ * **Re-rendering:** the hook itself does NOT force a React render on signal
57
+ * change the callback drives re-rendering by calling setState with the new
58
+ * signal value (as in the example above). This lets React's setState bailout
59
+ * skip renders when the derived value is unchanged; an unconditional
60
+ * force-update here previously caused a wasted render per notification even
61
+ * when the callback's setState bailed. If you need to re-render on every
62
+ * notification while reading signals during render, mirror the signal value
63
+ * into React state inside the callback.
50
64
  *
51
65
  * **Implementation note:** We wrap the callback in Signal.Computed because
52
66
  * Signal.subtle.Watcher cannot automatically track arbitrary function calls.
53
- * The Computed handles dependency tracking, and the Watcher monitors it.
54
- *
55
- * **Memory safety (Phase 29):**
56
- * - `disposed` flag prevents post-cleanup callback execution: if cleanup is
57
- * called before a pending microtask fires, the microtask returns early.
58
- * - `needsEnqueue` guard dedups rapid synchronous signal changes: only one
59
- * microtask is ever queued per batch of synchronous mutations.
67
+ * The Computed handles dependency tracking; watchSignal evaluates it (which
68
+ * runs the callback) whenever any tracked signal changes.
60
69
  */
61
- export declare const useSignalEffect: (callback: () => void | (() => void)) => void;
70
+ export declare const useSignalEffect: (callback: () => void | (() => void), deps?: DependencyList) => void;
62
71
  //# sourceMappingURL=useSignalEffect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSignalEffect.d.ts","sourceRoot":"","sources":["../src/useSignalEffect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,KAAG,IA+DrE,CAAC"}
1
+ {"version":3,"file":"useSignalEffect.d.ts","sourceRoot":"","sources":["../src/useSignalEffect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAS5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,eAAO,MAAM,eAAe,GAC3B,UAAU,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EACnC,OAAM,cAAmB,KACvB,IA0CF,CAAC"}
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * @packageDocumentation
5
5
  */
6
- import { useEffect, useReducer, useRef } from "react";
7
- import { Signal } from "@xmachines/play-signals";
6
+ import { useEffect, useRef } from "react";
7
+ import { Signal, watchSignal } from "@xmachines/play-signals";
8
8
  /**
9
9
  * Marker symbol returned by effect Computed to satisfy type requirements
10
10
  * The actual value doesn't matter - we only care about side effects
@@ -13,32 +13,40 @@ const EFFECT_RUN_MARKER = Symbol("effect-run");
13
13
  /**
14
14
  * React hook that subscribes to signal changes and runs effect callback
15
15
  *
16
- * Wraps Signal.subtle.Watcher to automatically track signal dependencies
17
- * accessed in the callback. When any tracked signal changes, the callback
18
- * re-runs and React component re-renders.
16
+ * Wraps the callback in a Signal.Computed to automatically track signal
17
+ * dependencies accessed inside it, then delegates the watcher lifecycle
18
+ * (microtask batching, re-arming, disposal) to `watchSignal` from
19
+ * `@xmachines/play-signals` — the single canonical implementation shared
20
+ * across framework renderers.
19
21
  *
20
- * Architecture (per RESEARCH.md Pattern 3):
22
+ * Architecture:
21
23
  * - Uses Signal.Computed to wrap callback for automatic dependency tracking
22
- * - Signal.subtle.Watcher monitors the Computed for changes
24
+ * - watchSignal owns the Signal.subtle.Watcher lifecycle (Phase 29 memory safety)
23
25
  * - Microtask batching coalesces rapid signal updates
24
- * - Forces React re-render via useReducer when signals change
26
+ * - Re-rendering is driven by the callback's own setState (see remarks)
25
27
  * - Handles cleanup on unmount to prevent memory leaks
26
28
  *
27
29
  * Invariant: Signal-Only Reactivity - Signals accessed in callback are watched.
28
30
  * Invariant: Passive Infrastructure - React observes signals and does not control them.
29
31
  *
30
32
  * @param callback - Effect function that accesses signals. Can return cleanup function.
33
+ * @param deps - Optional dependency list (like useEffect). When any dependency
34
+ * changes, the watcher and Computed are torn down and recreated, re-tracking
35
+ * signals from scratch. Defaults to `[]` (subscribe once per mount). Pass this
36
+ * when the identity of the object whose signals you read can change over the
37
+ * component's lifetime (e.g. an `actor` prop) — otherwise the watcher keeps
38
+ * tracking the OLD object's signals forever.
31
39
  *
32
40
  * @example
33
41
  * ```typescript
34
42
  * const MyComponent = ({ actor }) => {
35
43
  * const [view, setView] = useState(null);
36
44
  *
37
- * // Subscribe to actor.currentView signal
45
+ * // Subscribe to actor.currentView signal; re-subscribe if the actor swaps
38
46
  * useSignalEffect(() => {
39
47
  * const currentView = actor.currentView.get();
40
48
  * setView(currentView);
41
- * });
49
+ * }, [actor]);
42
50
  *
43
51
  * return <div>{view?.component}</div>;
44
52
  * };
@@ -48,35 +56,31 @@ const EFFECT_RUN_MARKER = Symbol("effect-run");
48
56
  * **CRITICAL:** Signals must be accessed unconditionally (no if statements).
49
57
  * Conditional signal access breaks automatic dependency tracking.
50
58
  *
51
- * **Performance:** Microtask batching (queueMicrotask) prevents React thrashing
52
- * when multiple signals update rapidly. Per signal-polyfill README pattern.
59
+ * **Performance:** Microtask batching (queueMicrotask, inside watchSignal)
60
+ * prevents React thrashing when multiple signals update rapidly.
53
61
  *
54
- * **Why forceUpdate:** React needs useState/useReducer to trigger re-render cycle.
55
- * Signal changes won't automatically re-render React components without forcing
56
- * update via state change.
62
+ * **Re-rendering:** the hook itself does NOT force a React render on signal
63
+ * change the callback drives re-rendering by calling setState with the new
64
+ * signal value (as in the example above). This lets React's setState bailout
65
+ * skip renders when the derived value is unchanged; an unconditional
66
+ * force-update here previously caused a wasted render per notification even
67
+ * when the callback's setState bailed. If you need to re-render on every
68
+ * notification while reading signals during render, mirror the signal value
69
+ * into React state inside the callback.
57
70
  *
58
71
  * **Implementation note:** We wrap the callback in Signal.Computed because
59
72
  * Signal.subtle.Watcher cannot automatically track arbitrary function calls.
60
- * The Computed handles dependency tracking, and the Watcher monitors it.
61
- *
62
- * **Memory safety (Phase 29):**
63
- * - `disposed` flag prevents post-cleanup callback execution: if cleanup is
64
- * called before a pending microtask fires, the microtask returns early.
65
- * - `needsEnqueue` guard dedups rapid synchronous signal changes: only one
66
- * microtask is ever queued per batch of synchronous mutations.
73
+ * The Computed handles dependency tracking; watchSignal evaluates it (which
74
+ * runs the callback) whenever any tracked signal changes.
67
75
  */
68
- export const useSignalEffect = (callback) => {
76
+ export const useSignalEffect = (callback, deps = []) => {
69
77
  // Store callback in a ref so the effect closure always calls the latest version
70
78
  // WITHOUT triggering watcher teardown/re-setup on each render (standard React ref pattern)
71
79
  const callbackRef = useRef(callback);
72
80
  // Assignment outside useEffect keeps ref current without triggering re-effect
73
81
  callbackRef.current = callback;
74
- // Force re-render when signal changes (React needs state change to re-render)
75
- const [, forceUpdate] = useReducer((x) => x + 1, 0);
76
82
  useEffect(() => {
77
83
  let cleanup;
78
- let needsEnqueue = true;
79
- let disposed = false;
80
84
  // Wrap callback in a Computed to automatically track dependencies
81
85
  // The Computed will re-evaluate when any accessed signal changes
82
86
  const effect = new Signal.Computed(() => {
@@ -88,37 +92,23 @@ export const useSignalEffect = (callback) => {
88
92
  // Return marker value (Computed requires a return value)
89
93
  return EFFECT_RUN_MARKER;
90
94
  });
91
- // Create watcher to detect when Computed needs re-evaluation
92
- const watcher = new Signal.subtle.Watcher(() => {
93
- // Batching flag prevents multiple microtasks for rapid changes
94
- if (disposed || !needsEnqueue)
95
- return;
96
- needsEnqueue = false;
97
- // Schedule microtask to batch updates (prevent React thrashing)
98
- queueMicrotask(() => {
99
- if (disposed)
100
- return;
101
- needsEnqueue = true;
102
- // Re-evaluate the Computed (runs callback with new signal values)
103
- effect.get();
104
- // Force React re-render
105
- forceUpdate();
106
- // Re-watch for next change
107
- watcher.watch();
108
- });
109
- });
110
- // Watch the Computed signal
111
- watcher.watch(effect);
95
+ // watchSignal owns the watcher lifecycle: microtask batching, disposed
96
+ // guard, and re-arming after each notification (Phase 29 memory safety
97
+ // lives there single source of truth, no copy-pasted watcher code).
98
+ // Reading the Computed inside watchSignal re-evaluates it, which runs the
99
+ // user callback; re-rendering is the callback's job (setState), so no
100
+ // extra work is needed in onValue.
101
+ const unwatch = watchSignal(effect, () => { });
112
102
  // Initial run of callback (via Computed)
113
103
  effect.get();
114
- // Cleanup on unmount
104
+ // Cleanup on unmount or deps change
115
105
  return () => {
116
- disposed = true;
106
+ // Stop receiving signal updates (idempotent, disposes pending microtasks)
107
+ unwatch();
117
108
  if (typeof cleanup === "function")
118
109
  cleanup();
119
- // Unwatch to stop receiving signal updates
120
- watcher.unwatch(effect);
121
110
  };
122
- }, []); // [] dep array: watcher created ONCE per mount, not once per render
111
+ // oxlint-disable-next-line exhaustive-deps -- deps forwarded from caller; callback intentionally excluded (ref pattern)
112
+ }, deps);
123
113
  };
124
114
  //# sourceMappingURL=useSignalEffect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSignalEffect.js","sourceRoot":"","sources":["../src/useSignalEffect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEjD;;;GAGG;AACH,MAAM,iBAAiB,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAmC,EAAQ,EAAE;IAC5E,gFAAgF;IAChF,2FAA2F;IAC3F,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrC,8EAA8E;IAC9E,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;IAE/B,8EAA8E;IAC9E,MAAM,CAAC,EAAE,WAAW,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAEpD,SAAS,CAAC,GAAG,EAAE;QACd,IAAI,OAA4B,CAAC;QACjC,IAAI,YAAY,GAAG,IAAI,CAAC;QACxB,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,kEAAkE;QAClE,iEAAiE;QACjE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE;YACvC,mCAAmC;YACnC,IAAI,OAAO,OAAO,KAAK,UAAU;gBAAE,OAAO,EAAE,CAAC;YAE7C,kEAAkE;YAClE,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC;YAEhC,yDAAyD;YACzD,OAAO,iBAAiB,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,6DAA6D;QAC7D,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;YAC9C,+DAA+D;YAC/D,IAAI,QAAQ,IAAI,CAAC,YAAY;gBAAE,OAAO;YACtC,YAAY,GAAG,KAAK,CAAC;YACrB,gEAAgE;YAChE,cAAc,CAAC,GAAG,EAAE;gBACnB,IAAI,QAAQ;oBAAE,OAAO;gBACrB,YAAY,GAAG,IAAI,CAAC;gBAEpB,kEAAkE;gBAClE,MAAM,CAAC,GAAG,EAAE,CAAC;gBAEb,wBAAwB;gBACxB,WAAW,EAAE,CAAC;gBAEd,2BAA2B;gBAC3B,OAAO,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,4BAA4B;QAC5B,OAAO,CAAC,KAAK,CAAC,MAAkC,CAAC,CAAC;QAElD,yCAAyC;QACzC,MAAM,CAAC,GAAG,EAAE,CAAC;QAEb,qBAAqB;QACrB,OAAO,GAAG,EAAE;YACX,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,OAAO,OAAO,KAAK,UAAU;gBAAE,OAAO,EAAE,CAAC;YAC7C,2CAA2C;YAC3C,OAAO,CAAC,OAAO,CAAC,MAAkC,CAAC,CAAC;QACrD,CAAC,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,sEAAsE;AAC/E,CAAC,CAAC"}
1
+ {"version":3,"file":"useSignalEffect.js","sourceRoot":"","sources":["../src/useSignalEffect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE1C,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE9D;;;GAGG;AACH,MAAM,iBAAiB,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC9B,QAAmC,EACnC,OAAuB,EAAE,EAClB,EAAE;IACT,gFAAgF;IAChF,2FAA2F;IAC3F,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrC,8EAA8E;IAC9E,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;IAE/B,SAAS,CAAC,GAAG,EAAE;QACd,IAAI,OAA4B,CAAC;QAEjC,kEAAkE;QAClE,iEAAiE;QACjE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE;YACvC,mCAAmC;YACnC,IAAI,OAAO,OAAO,KAAK,UAAU;gBAAE,OAAO,EAAE,CAAC;YAE7C,kEAAkE;YAClE,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC;YAEhC,yDAAyD;YACzD,OAAO,iBAAiB,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,uEAAuE;QACvE,uEAAuE;QACvE,sEAAsE;QACtE,0EAA0E;QAC1E,sEAAsE;QACtE,mCAAmC;QACnC,MAAM,OAAO,GAAG,WAAW,CAAC,MAAkC,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAE1E,yCAAyC;QACzC,MAAM,CAAC,GAAG,EAAE,CAAC;QAEb,oCAAoC;QACpC,OAAO,GAAG,EAAE;YACX,0EAA0E;YAC1E,OAAO,EAAE,CAAC;YACV,IAAI,OAAO,OAAO,KAAK,UAAU;gBAAE,OAAO,EAAE,CAAC;QAC9C,CAAC,CAAC;QACF,wHAAwH;IACzH,CAAC,EAAE,IAAI,CAAC,CAAC;AACV,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmachines/play-react",
3
- "version": "1.0.0-beta.53",
3
+ "version": "1.0.0-beta.54",
4
4
  "description": "React renderer for XMachines Play architecture with signal-driven rendering",
5
5
  "keywords": [
6
6
  "actor",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsc --build",
39
- "clean": "rm -rf dist *.tsbuildinfo coverage .vitest-attachments test/browser/__screenshots__ node_modules/.svelte2tsx-*",
39
+ "clean": "rm -rf dist *.tsbuildinfo coverage .vitest-attachments test/browser/__screenshots__ node_modules/.svelte2tsx-* node_modules/.vite*",
40
40
  "lint": "oxlint .",
41
41
  "format": "oxfmt .",
42
42
  "test": "vitest",
@@ -45,9 +45,9 @@
45
45
  "prepublishOnly": "npm run build"
46
46
  },
47
47
  "dependencies": {
48
- "@xmachines/play": "1.0.0-beta.53",
49
- "@xmachines/play-actor": "1.0.0-beta.53",
50
- "@xmachines/play-signals": "1.0.0-beta.53"
48
+ "@xmachines/play": "1.0.0-beta.54",
49
+ "@xmachines/play-actor": "1.0.0-beta.54",
50
+ "@xmachines/play-signals": "1.0.0-beta.54"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@json-render/core": "^0.18.0",
@@ -58,7 +58,9 @@
58
58
  "@types/node": "^25.6.0",
59
59
  "@types/react": "^19.2.14",
60
60
  "@types/react-dom": "^19.2.3",
61
- "@xmachines/shared": "1.0.0-beta.53",
61
+ "@vitejs/plugin-react": "^6.0.1",
62
+ "@vitest/browser-playwright": "^4.1.5",
63
+ "@xmachines/shared": "1.0.0-beta.54",
62
64
  "@xstate/store": "^3.17.0",
63
65
  "jsdom": "^29.1.0",
64
66
  "oxfmt": "^0.47.0",
@@ -67,7 +69,8 @@
67
69
  "react-dom": "^19.2.5",
68
70
  "typescript": "^5.9.3 || ^6.0.3",
69
71
  "vitest": "^4.1.5",
70
- "xstate": "^5.31.0"
72
+ "xstate": "^5.31.0",
73
+ "zod": "^4.4.1"
71
74
  },
72
75
  "peerDependencies": {
73
76
  "@json-render/core": "^0.18.0",