You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(hooks): auto-marshal UseState/UseReducer setters to UI thread (#212)
UseState and UseReducer setters called from a background thread (Task.Run,
PeriodicTimer, callbacks after ConfigureAwait(false)) previously hit a
[Conditional("DEBUG")] AssertUIThread that either threw into a discarded
Task (DEBUG) or compiled out entirely (RELEASE), producing silent UI
update loss in both flavors.
Replace the DEBUG-only assert with an always-on UI-thread check that
auto-marshals the write and the resulting rerender onto the captured
ReactorApp.UIDispatcher when called off-thread. The hot path adds one
TLS read + int compare + branch (~1-2 ns); the marshal allocation is
only paid on the off-thread path, where it's swamped by cross-thread
dispatch cost. When no UI dispatcher has been captured (test/headless
contexts), the off-thread call now throws a loud InvalidOperationException
in both DEBUG and RELEASE instead of silently racing.
threadSafe: true retains its existing locked-in-place semantics for
callers that need many concurrent writers to serialize without an
intervening UI tick.
Adds a NonThreadSafeAutoMarshal selftest that mounts a real WinUI host
and reproduces the issue's Task.Run + PeriodicTimer pattern with default
hooks. Documents the auto-marshal contract in hooks.md and effects.md
(first mention of `threadSafe` in the guide).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments