Repository navigation
fix: keep useUniwind in sync when compiled by React Compiler - #719
Draft
dlebedynskyi wants to merge 1 commit into
Draft
dlebedynskyi wants to merge 1 commit into
dlebedynskyi wants to merge 1 commit into
Conversation
useUniwind reads Uniwind.currentTheme and Uniwind.hasAdaptiveThemes during render through useSnapshot. When uniwind's source goes through babel-plugin-react-compiler (a workspace-linked copy, or a compiler `sources` option that includes node_modules), the compiler caches the getSnapshot() call on getSnapshot, a module-level function that never changes. The theme subscription still re-renders the component, but the hook keeps returning the value from its first render, so useUniwind reports the initial theme after Uniwind.setTheme on native and web. Opt useSnapshot out with 'use no memo', as useStyle already does. Without the compiler the directive does nothing. The native Jest config now also runs the suite with src compiled by babel-plugin-react-compiler 1.0.0, which bun.lock already resolves through babel-preset-expo. Without the fix, that run fails `ScopedTheme › useUniwind` and `freeze › external stores catch up after a suspended tree is revealed`.
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I ran into this in a monorepo where uniwind is a workspace package, so React Compiler compiles its source along with the app. With the compiler applied to
src, the native tests showeduseUniwindstuck on the first theme:ScopedTheme › useUniwindstill readlightaftersetTheme('dark'). Claude was fixing it.When uniwind's source is compiled by React Compiler,
useUniwindkeeps returning the theme from its first render.Uniwind.setTheme('dark')re-renders the component, butthemestayslight.useSnapshotreadsUniwind.currentThemeduring render. The compiler treatsgetSnapshot()as pure and caches it ongetSnapshot, which is a module-level function and never changes (babel-plugin-react-compiler1.0.0):The theme listener still fires and
rerender()runs, but the hook returns the cached$[1]. This affects native and web, sinceuseUniwind.tsis shared.The fix adds
'use no memo'touseSnapshot, asuseStylealready does. Without the compiler the directive does nothing.I also checked the other hooks that read runtime state under the compiler.
useResolveClassNamesand thewithUniwinddependency hooks read the store only in reducers and effects, so they stay correct when compiled.useCSSVariablehas the same render-time read, but the compiler skips it ("Reassigninginitializedafter render has completed"), so it isn't affected today. I can add the directive there too if you'd prefer to be explicit.Tests
jest.config.native.jsnow runs the native suite as two projects:native(unchanged) andnative-react-compiler, withsrccompiled bybabel-plugin-react-compiler. The plugin is added as a devDependency at 1.0.0, the versionbun.lockalready has throughbabel-preset-expo. The only lockfile change is that devDependency line. Without the fix,native-react-compilerfails:ScopedTheme › useUniwind: expecteddark, receivedlightfreeze › external stores catch up after a suspended tree is revealed: expecteddark, receivedlightWith the fix, both projects pass, 203/203 tests each. The web
freezetest fails the same way under the compiler and passes with the fix. I checked that locally with a throwaway Vitest config that isn't part of this PR.When it happens
Normal installs aren't affected. React Compiler's default
sourcesskips paths that containnode_modules, andbabel-preset-expodoesn't run the compiler on node modules either. It happens when the compiler reaches uniwind's source:node_modules, for example a workspace package in a monorepo or a symlinked local checkoutsourcesto includenode_modules