Skip to content

fix(hooks): no-op stale property setter calls after dispose#316

Open
mfazekas wants to merge 2 commits into
mainfrom
fix/stale-setter-write
Open

fix(hooks): no-op stale property setter calls after dispose#316
mfazekas wants to merge 2 commits into
mainfrom
fix/stale-setter-write

Conversation

@mfazekas

@mfazekas mfazekas commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

A setter returned by useRiveNumber/useRiveString/etc. can be captured in a stale closure (async callback, timeout) and fire after its property was disposed by a deps change or unmount. The write then reaches the disposed hybrid and throws Cannot set hybrid property ... NativeState is null — fatal when uncaught in a release app.

The fix routes writes through the liveRef that useDisposableMemo already maintains (nulled at dispose time) — the same guard useRiveTrigger uses. A write after unmount warns and no-ops (with the path and likely cause) instead of throwing; a write captured before a deps change targets the hook's current property, matching useRiveTrigger semantics. property stays in the useCallback deps so the setter identity still changes with the property.

Tests: jest cases for the after-unmount no-op+warn and the deps-change redirect, plus an on-device harness test (staleSetterWrite.test.tsx) that fails on the unguarded hook — verified on the Android emulator on both backends.

mfazekas added 2 commits July 6, 2026 06:08
A setter returned by useRiveNumber/useRiveString/etc. can be captured in a
stale closure (async callback, timeout) and fire after its property was
disposed by a deps change or unmount. The write then hits the disposed
hybrid and throws "Cannot set hybrid property ... NativeState is null" -
fatal when uncaught in release.

Route writes through the liveRef that useDisposableMemo already maintains
(nulled at dispose time), the same guard useRiveTrigger uses, so stale
writes become safe no-ops. Adds jest regression tests plus an on-device
harness test that fails on the unguarded hook.
Mirror useRiveTrigger: instead of silently ignoring a setter call on a
missing property, warn with the path and the likely cause (stale closure
after unmount vs. instance still loading) so misuse stays visible without
crashing. Also reformat with prettier 3.8.3 (the version main resolves;
CI lint failed on formatting produced by 3.6.2).
@mfazekas mfazekas requested a review from HayesGordon July 6, 2026 05:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant