@xmachines/play-react 1.0.0-beta.8 → 1.0.0-beta.9
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 +38 -2
- package/dist/PlayErrorBoundary.d.ts +47 -0
- package/dist/PlayErrorBoundary.d.ts.map +1 -0
- package/dist/PlayErrorBoundary.js +42 -0
- package/dist/PlayErrorBoundary.js.map +1 -0
- package/dist/PlayRenderer.d.ts.map +1 -1
- package/dist/PlayRenderer.js +2 -1
- package/dist/PlayRenderer.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/useSignalEffect.d.ts.map +1 -1
- package/dist/useSignalEffect.js +13 -6
- package/dist/useSignalEffect.js.map +1 -1
- package/package.json +7 -9
package/README.md
CHANGED
|
@@ -28,12 +28,14 @@ npm install @xmachines/play-react
|
|
|
28
28
|
|
|
29
29
|
- `PlayRenderer`
|
|
30
30
|
- `useSignalEffect`
|
|
31
|
+
- `PlayErrorBoundary`
|
|
31
32
|
- `PlayRendererProps` (type)
|
|
33
|
+
- `PlayErrorBoundaryProps` (type)
|
|
32
34
|
|
|
33
35
|
**Peer dependencies:**
|
|
34
36
|
|
|
35
|
-
- `react` ^18.0.0
|
|
36
|
-
- `react-dom` ^18.0.0
|
|
37
|
+
- `react` ^18.0.0 || ^19.0.0 — React runtime
|
|
38
|
+
- `react-dom` ^18.0.0 || ^19.0.0 — React DOM renderer
|
|
37
39
|
|
|
38
40
|
## Quick Start
|
|
39
41
|
|
|
@@ -175,6 +177,40 @@ function RouteDisplay({ actor }: { actor: AbstractActor<any> }) {
|
|
|
175
177
|
}
|
|
176
178
|
```
|
|
177
179
|
|
|
180
|
+
### PlayErrorBoundary
|
|
181
|
+
|
|
182
|
+
React class component error boundary for catching catalog component render errors.
|
|
183
|
+
|
|
184
|
+
`PlayRenderer` wraps its render output in `PlayErrorBoundary` automatically. You can also use it directly to wrap any component that may throw during render.
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
interface PlayErrorBoundaryProps {
|
|
188
|
+
fallback?: React.ReactNode; // UI shown when a child throws (default: null)
|
|
189
|
+
children: React.ReactNode;
|
|
190
|
+
onError?: (error: Error, info: React.ErrorInfo) => void; // Forward to Sentry, Datadog, etc.
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Props:**
|
|
195
|
+
|
|
196
|
+
- `fallback` — ReactNode rendered when a child component throws. Defaults to `null`.
|
|
197
|
+
- `onError` — Optional callback forwarded on every caught error. Use for production observability (Sentry, Datadog, custom logging).
|
|
198
|
+
|
|
199
|
+
**Example:**
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
import { PlayErrorBoundary } from "@xmachines/play-react";
|
|
203
|
+
|
|
204
|
+
<PlayErrorBoundary
|
|
205
|
+
fallback={<div className="error">Something went wrong.</div>}
|
|
206
|
+
onError={(error) => Sentry.captureException(error)}
|
|
207
|
+
>
|
|
208
|
+
<YourCatalogComponent />
|
|
209
|
+
</PlayErrorBoundary>;
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Works with React 18 and React 19. Uses the standard class component `componentDidCatch` + `getDerivedStateFromError` pattern.
|
|
213
|
+
|
|
178
214
|
**Complete API:** See [API Documentation](../../docs/api/@xmachines/play-react)
|
|
179
215
|
|
|
180
216
|
## Examples
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PlayErrorBoundary - React error boundary for catching catalog component render errors
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import React from "react";
|
|
7
|
+
/**
|
|
8
|
+
* Props for PlayErrorBoundary
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export interface PlayErrorBoundaryProps {
|
|
13
|
+
/** Fallback UI to render when a child component throws. Defaults to null. */
|
|
14
|
+
fallback?: React.ReactNode;
|
|
15
|
+
/** Child components to render */
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
/** Optional error handler callback — forwards errors to observability tools (Sentry, etc.) */
|
|
18
|
+
onError?: (error: Error, info: React.ErrorInfo) => void;
|
|
19
|
+
}
|
|
20
|
+
interface PlayErrorBoundaryState {
|
|
21
|
+
hasError: boolean;
|
|
22
|
+
error: Error | null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* React class component error boundary for catching catalog component render errors.
|
|
26
|
+
*
|
|
27
|
+
* Wraps catalog component renders so failures are caught and forwarded to standard
|
|
28
|
+
* React error boundary protocol. Consumers can attach the `onError` prop to forward
|
|
29
|
+
* errors to production observability tools (Sentry, Datadog, etc.).
|
|
30
|
+
*
|
|
31
|
+
* Per CONS-14: Class component pattern works with all React versions (18 and 19).
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* <PlayErrorBoundary fallback={<div>Something went wrong</div>} onError={Sentry.captureException}>
|
|
36
|
+
* <CatalogComponent {...props} />
|
|
37
|
+
* </PlayErrorBoundary>
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class PlayErrorBoundary extends React.Component<PlayErrorBoundaryProps, PlayErrorBoundaryState> {
|
|
41
|
+
constructor(props: PlayErrorBoundaryProps);
|
|
42
|
+
static getDerivedStateFromError(error: Error): PlayErrorBoundaryState;
|
|
43
|
+
componentDidCatch(error: Error, info: React.ErrorInfo): void;
|
|
44
|
+
render(): React.ReactNode;
|
|
45
|
+
}
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=PlayErrorBoundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlayErrorBoundary.d.ts","sourceRoot":"","sources":["../src/PlayErrorBoundary.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACtC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,iCAAiC;IACjC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,8FAA8F;IAC9F,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC;CACxD;AAED,UAAU,sBAAsB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,iBAAkB,SAAQ,KAAK,CAAC,SAAS,CACrD,sBAAsB,EACtB,sBAAsB,CACtB;gBACY,KAAK,EAAE,sBAAsB;IAKzC,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,sBAAsB;IAI5D,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI;IAK5D,MAAM,IAAI,KAAK,CAAC,SAAS;CAMlC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PlayErrorBoundary - React error boundary for catching catalog component render errors
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
import React from "react";
|
|
7
|
+
/**
|
|
8
|
+
* React class component error boundary for catching catalog component render errors.
|
|
9
|
+
*
|
|
10
|
+
* Wraps catalog component renders so failures are caught and forwarded to standard
|
|
11
|
+
* React error boundary protocol. Consumers can attach the `onError` prop to forward
|
|
12
|
+
* errors to production observability tools (Sentry, Datadog, etc.).
|
|
13
|
+
*
|
|
14
|
+
* Per CONS-14: Class component pattern works with all React versions (18 and 19).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* <PlayErrorBoundary fallback={<div>Something went wrong</div>} onError={Sentry.captureException}>
|
|
19
|
+
* <CatalogComponent {...props} />
|
|
20
|
+
* </PlayErrorBoundary>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class PlayErrorBoundary extends React.Component {
|
|
24
|
+
constructor(props) {
|
|
25
|
+
super(props);
|
|
26
|
+
this.state = { hasError: false, error: null };
|
|
27
|
+
}
|
|
28
|
+
static getDerivedStateFromError(error) {
|
|
29
|
+
return { hasError: true, error };
|
|
30
|
+
}
|
|
31
|
+
componentDidCatch(error, info) {
|
|
32
|
+
console.error("[PlayErrorBoundary] Component render error:", error, info);
|
|
33
|
+
this.props.onError?.(error, info);
|
|
34
|
+
}
|
|
35
|
+
render() {
|
|
36
|
+
if (this.state.hasError) {
|
|
37
|
+
return this.props.fallback ?? null;
|
|
38
|
+
}
|
|
39
|
+
return this.props.children;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=PlayErrorBoundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlayErrorBoundary.js","sourceRoot":"","sources":["../src/PlayErrorBoundary.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAqB1B;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK,CAAC,SAG5C;IACA,YAAY,KAA6B;QACxC,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,CAAC,wBAAwB,CAAC,KAAY;QAC3C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IAEQ,iBAAiB,CAAC,KAAY,EAAE,IAAqB;QAC7D,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1E,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAEQ,MAAM;QACd,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC;QACpC,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC5B,CAAC;CACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"PlayRenderer.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA+CpD,CAAC"}
|
package/dist/PlayRenderer.js
CHANGED
|
@@ -6,6 +6,7 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
|
6
6
|
*/
|
|
7
7
|
import React, { useState } from "react";
|
|
8
8
|
import { useSignalEffect } from "./useSignalEffect.js";
|
|
9
|
+
import { PlayErrorBoundary } from "./PlayErrorBoundary.js";
|
|
9
10
|
/**
|
|
10
11
|
* Main renderer component that subscribes to actor signals and renders UI
|
|
11
12
|
*
|
|
@@ -82,6 +83,6 @@ export const PlayRenderer = ({ actor, components, fallback = null, }) => {
|
|
|
82
83
|
}
|
|
83
84
|
// Render with props from actor + send function
|
|
84
85
|
// bind(actor) ensures 'this' context is correct when components call send()
|
|
85
|
-
return _jsx(Component, { ...view.props, send: actor.send.bind(actor) });
|
|
86
|
+
return (_jsx(PlayErrorBoundary, { fallback: fallback, children: _jsx(Component, { ...view.props, send: actor.send.bind(actor) }) }));
|
|
86
87
|
};
|
|
87
88
|
//# sourceMappingURL=PlayRenderer.js.map
|
package/dist/PlayRenderer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"PlayRenderer.js","sourceRoot":"","sources":["../src/PlayRenderer.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAI3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgC,CAAC,EACzD,KAAK,EACL,UAAU,EACV,QAAQ,GAAG,IAAI,GACf,EAAE,EAAE;IACJ,mEAAmE;IACnE,qEAAqE;IACrE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAsB,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;IAErF,8BAA8B;IAC9B,eAAe,CAAC,GAAG,EAAE;QACpB,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;QAC5C,OAAO,CAAC,WAAW,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,2BAA2B;IAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACxB,CAAC;IAED,sDAAsD;IACtD,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CACZ,yBAAyB,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI;YACtE,4BAA4B,IAAI,CAAC,SAAS,IAAI,CAC/C,CAAC;QACF,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACxB,CAAC;IAED,iCAAiC;IACjC,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE7C,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CACZ,cAAc,IAAI,CAAC,SAAS,0BAA0B;YACrD,yBAAyB,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9D,CAAC;QACF,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACxB,CAAC;IAED,+CAA+C;IAC/C,4EAA4E;IAC5E,OAAO,CACN,KAAC,iBAAiB,IAAC,QAAQ,EAAE,QAAQ,YACpC,KAAC,SAAS,OAAK,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAI,GACxC,CACpB,CAAC;AACH,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,5 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export { PlayRenderer } from "./PlayRenderer.js";
|
|
16
16
|
export { useSignalEffect } from "./useSignalEffect.js";
|
|
17
|
+
export { PlayErrorBoundary } from "./PlayErrorBoundary.js";
|
|
17
18
|
export type { PlayRendererProps } from "./types.js";
|
|
19
|
+
export type { PlayErrorBoundaryProps } from "./PlayErrorBoundary.js";
|
|
18
20
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG3D,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,eAAe;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,eAAe;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSignalEffect.d.ts","sourceRoot":"","sources":["../src/useSignalEffect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,KAAG,
|
|
1
|
+
{"version":3,"file":"useSignalEffect.d.ts","sourceRoot":"","sources":["../src/useSignalEffect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,KAAG,IA6DrE,CAAC"}
|
package/dist/useSignalEffect.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
|
-
import { useEffect, useReducer } from "react";
|
|
6
|
+
import { useEffect, useReducer, useRef } from "react";
|
|
7
7
|
import { Signal } from "@xmachines/play-signals";
|
|
8
8
|
/**
|
|
9
9
|
* Marker symbol returned by effect Computed to satisfy type requirements
|
|
@@ -60,6 +60,11 @@ const EFFECT_RUN_MARKER = Symbol("effect-run");
|
|
|
60
60
|
* The Computed handles dependency tracking, and the Watcher monitors it.
|
|
61
61
|
*/
|
|
62
62
|
export const useSignalEffect = (callback) => {
|
|
63
|
+
// Store callback in a ref so the effect closure always calls the latest version
|
|
64
|
+
// WITHOUT triggering watcher teardown/re-setup on each render (standard React ref pattern)
|
|
65
|
+
const callbackRef = useRef(callback);
|
|
66
|
+
// Assignment outside useEffect keeps ref current without triggering re-effect
|
|
67
|
+
callbackRef.current = callback;
|
|
63
68
|
// Force re-render when signal changes (React needs state change to re-render)
|
|
64
69
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
65
70
|
useEffect(() => {
|
|
@@ -69,9 +74,10 @@ export const useSignalEffect = (callback) => {
|
|
|
69
74
|
// The Computed will re-evaluate when any accessed signal changes
|
|
70
75
|
const effect = new Signal.Computed(() => {
|
|
71
76
|
// Run cleanup from previous effect
|
|
72
|
-
cleanup
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
if (typeof cleanup === "function")
|
|
78
|
+
cleanup();
|
|
79
|
+
// Run user callback via ref (always latest version, no dep churn)
|
|
80
|
+
cleanup = callbackRef.current();
|
|
75
81
|
// Return marker value (Computed requires a return value)
|
|
76
82
|
return EFFECT_RUN_MARKER;
|
|
77
83
|
});
|
|
@@ -98,10 +104,11 @@ export const useSignalEffect = (callback) => {
|
|
|
98
104
|
effect.get();
|
|
99
105
|
// Cleanup on unmount
|
|
100
106
|
return () => {
|
|
101
|
-
cleanup
|
|
107
|
+
if (typeof cleanup === "function")
|
|
108
|
+
cleanup();
|
|
102
109
|
// Unwatch to stop receiving signal updates
|
|
103
110
|
watcher.unwatch(effect);
|
|
104
111
|
};
|
|
105
|
-
}, [
|
|
112
|
+
}, []); // ← [] dep array: watcher created ONCE per mount, not once per render
|
|
106
113
|
};
|
|
107
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,OAAO,CAAC;
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;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;QAExB,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,YAAY,EAAE,CAAC;gBAClB,YAAY,GAAG,KAAK,CAAC;gBACrB,gEAAgE;gBAChE,cAAc,CAAC,GAAG,EAAE;oBACnB,YAAY,GAAG,IAAI,CAAC;oBAEpB,kEAAkE;oBAClE,MAAM,CAAC,GAAG,EAAE,CAAC;oBAEb,wBAAwB;oBACxB,WAAW,EAAE,CAAC;oBAEd,2BAA2B;oBAC3B,OAAO,CAAC,KAAK,EAAE,CAAC;gBACjB,CAAC,CAAC,CAAC;YACJ,CAAC;QACF,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,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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmachines/play-react",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.9",
|
|
4
4
|
"description": "React renderer for XMachines Play architecture with signal-driven rendering",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"actor",
|
|
@@ -44,25 +44,23 @@
|
|
|
44
44
|
"prepublishOnly": "npm run build"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@xmachines/play-actor": "1.0.0-beta.
|
|
48
|
-
"@xmachines/play-catalog": "1.0.0-beta.
|
|
49
|
-
"@xmachines/play-signals": "1.0.0-beta.
|
|
47
|
+
"@xmachines/play-actor": "1.0.0-beta.9",
|
|
48
|
+
"@xmachines/play-catalog": "1.0.0-beta.9",
|
|
49
|
+
"@xmachines/play-signals": "1.0.0-beta.9"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@testing-library/jest-dom": "^6.9.1",
|
|
53
53
|
"@testing-library/react": "^16.3.2",
|
|
54
|
-
"@types/jsdom": "^28.0.1",
|
|
55
54
|
"@types/node": "^25.5.0",
|
|
56
55
|
"@types/react": "^19.2.14",
|
|
57
56
|
"@types/react-dom": "^19.2.3",
|
|
58
|
-
"@xmachines/shared": "1.0.0-beta.
|
|
59
|
-
"jsdom": "^29.0.0",
|
|
57
|
+
"@xmachines/shared": "1.0.0-beta.9",
|
|
60
58
|
"react": "^19.2.4",
|
|
61
59
|
"react-dom": "^19.2.4",
|
|
62
60
|
"typescript": "^5.9.3"
|
|
63
61
|
},
|
|
64
62
|
"peerDependencies": {
|
|
65
|
-
"react": "^18.
|
|
66
|
-
"react-dom": "^18.
|
|
63
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
64
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
67
65
|
}
|
|
68
66
|
}
|