Skip to content

Backport useSyncExternalStore - #24

Draft
christopher-buss wants to merge 1 commit into
Roblox:mainfrom
christopher-buss:sync-external-store
Draft

Backport useSyncExternalStore#24
christopher-buss wants to merge 1 commit into
Roblox:mainfrom
christopher-buss:sync-external-store

Conversation

@christopher-buss

Copy link
Copy Markdown

Backports the useSyncExternalStore hook from React 18

christopher-buss added a commit to christopher-buss/flux that referenced this pull request Aug 12, 2026
The install stays stock, so selectStoreHook answers with the shim exactly
as it does for a consumer. A second react-lua, patched with the
useSyncExternalStore backport from Roblox/react-luau#24, is mounted
beside it in the same test place and reached through #test/native-stack.

TS.getModule resolves by position, so the same compiled out/ mounted
inside that subtree binds to the patched React with no second
compilation. One run now proves both branches of selectStoreHook against
real Reacts, rather than one branch and a fake.

Two traps this hit, both now constraints in the package CLAUDE.md:
mounting one directory twice makes the specifier ambiguous to roblox-ts,
and a self-referential .d.ts collapses to any, which loses method-call
emit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
christopher-buss added a commit to christopher-buss/flux that referenced this pull request Aug 13, 2026
* feat(react)!: use React's useSyncExternalStore when it exists

Pick React's own store hook at module load when the running react-lua
carries it, else the ported shim. Same detection upstream's
use-sync-external-store/shim does, so a consumer who backports the hook
into their reconciler needs no change here.

The real hook takes subscribe straight through, which is only atomic on
a ConcurrentMode fiber. Flux therefore drops legacy root support: the
testing library is patched to createRoot plus renderer-owned act, and
one spec locks that.

BREAKING CHANGE: flux-react requires ReactRoblox.createRoot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(react): cover the native store hook in the same pass

The install stays stock, so selectStoreHook answers with the shim exactly
as it does for a consumer. A second react-lua, patched with the
useSyncExternalStore backport from Roblox/react-luau#24, is mounted
beside it in the same test place and reached through #test/native-stack.

TS.getModule resolves by position, so the same compiled out/ mounted
inside that subtree binds to the patched React with no second
compilation. One run now proves both branches of selectStoreHook against
real Reacts, rather than one branch and a fake.

Two traps this hit, both now constraints in the package CLAUDE.md:
mounting one directory twice makes the specifier ambiguous to roblox-ts,
and a self-referential .d.ts collapses to any, which loses method-call
emit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* ci: generate the native store hook projects on CI

CI installs with --ignore-scripts, so postinstall never ran the new
generator and the react test project could not read
@rbxts-native.project.json.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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