varResolver: a var() resolved from the :root/inline/universal fallback isn't guarded — a token provided via context after first render never re-resolves
Maintainer antworten meist innerhalb von 3 Tagen
Bewertung
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-3 Stunden
- Anfängerfreundlichkeit
- 25/100
- Issue-Typ
- Bug
- Klarheit
- Klar beschrieben
- Aktivitätsstatus
- Veraltet
- Tech-Stack
- react, react-native, typescript
Rechercherichtung
Start in src/native/styles/variables.ts, in varResolver, and compare the name in variables branch, which pushes a guard, with the fallback path after variableHistory.add(name), which does not. Linked PR #467 is already open against this, so check it before writing anything. Done means a test where a var() resolves from :root, a VariableContextProvider then supplies the token, and the mounted node re-resolves.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Summary
In varResolver (src/native/styles/variables.ts), a re-render dependency guard is recorded only on the name in variables (inherited VariableContext) path. When a var() is instead resolved from the inline / universal / :root fallback, the function returns without pushing a guard. As a result, a token that is absent from context at first render (so it resolves from :root) and is later provided via a nearer VariableContextProvider is never re-resolved on an already-mounted node — the node stays at the :root/fallback value permanently.
It's timing-sensitive: it only manifests when the context value arrives after the first paint of the consuming node. On a fast first paint the token is already in context (guarded → works); on a slower first paint (e.g. Android/Hermes committing before an async provider updates) the node latches the fallback value forever.
Version
Repro
A styled/useCssElement node whose var(--x) starts unset (resolves from :root) and is later given a value via a VariableContextProvider higher in the tree keeps the :root value — it never re-resolves when --x subsequently appears in context.
Concretely: render a node using var(--brand) where --brand is not yet provided by any context; later push --brand into a VariableContextProvider. The mounted node keeps the :root/fallback value instead of updating.
Root cause
varResolver pushes renderGuards.push(["v", name, variables[name]]) inside the if (name in variables) { … } branch and then returns. The other path — reached when name is not in variables (it runs variableHistory.add(name) and then the inline → universal → :root → fallback lookups) — returns without recording any guard for name. So testGuards watches nothing for that token, and a later context change for it never triggers re-resolution of the mounted node.
Proposed fix
Record a guard for the "currently absent from context" state as well — push renderGuards.push(["v", name, variables[name]]) immediately after variableHistory.add(name) (before the fallback lookups). variables[name] is undefined there, which is the correct sentinel: the guard then fires precisely when the token later appears in context, and there is no value shadow (the returned value is still the :root/fallback until context provides one). It terminates cleanly — exactly one extra re-resolve on the absent→present transition.
Context
We hit this in a production React Native app where channel/brand CSS variables are supplied asynchronously (fetched, then injected as a delta over the :root defaults). iOS happened to paint after the fetch (token in context → guarded → correct); Android painted before it and latched the default. We're currently carrying a local patch that applies the one-line fix above; filing upstream so it can live in the library. Happy to open a PR if that's useful.
(Distinct from #245, which is about a memory leak on re-render.)
- Vorherrschende Sprache
- TypeScript
- Sterne
- 166
- Forks
- 45
- Ø Merge
- 13 T. 14 Std.
- Gemergte PRs (30 T.)
- 1
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Keine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus nativewind/react-native-css
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
nativewind/react-native-css#545 ·
Maintainer antworten meist innerhalb von 3 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
nativewind/react-native-css#544 ·
Maintainer antworten meist innerhalb von 3 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
nativewind/react-native-css#543 ·
Maintainer antworten meist innerhalb von 3 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
nativewind/react-native-css#540 ·
Maintainer antworten meist innerhalb von 3 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
nativewind/react-native-css#538 ·
Maintainer antworten meist innerhalb von 3 Tagen
Alle Issues in nativewind/react-native-css
Ähnliche Issues
-
Shell: serve the home app's Cookie Policy on a hard reloadEvtl. vergeben @2001anshkaushik hat das heute übernommen. Offenfeature module:ai
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 88/100
rocketride-org/rocketride-server#2899 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 72/100
wazuh/wazuh-dashboard-plugins#9551 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
gofish-graphics/gofish-graphics#1252 ·
Maintainer antworten meist innerhalb von 1 Tag
-
optimization P3 size:XS
Schwierigkeit 1/5 1-3 Stunden Anfängerfreundlichkeit 88/100
josephfung/curia#2366 ·
Maintainer antworten meist innerhalb von 1 Tag
-
type:bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 65/100
nightgauge/nightgauge#2688 ·
Maintainer antworten meist innerhalb von 1 Tag