Skip to content

fix(views): accept null for a removed function prop - #1671

Open
lagudafuadtosin wants to merge 2 commits into
margelo:mainfrom
lagudafuadtosin:fix/view-function-prop-null
Open

lagudafuadtosin wants to merge 2 commits into
margelo:mainfrom
lagudafuadtosin:fix/view-function-prop-null

Conversation

@lagudafuadtosin

Copy link
Copy Markdown

ReactProp<T>::fromRawValue unwraps function props with asObject() before anything checks for null. When a view had a function prop on one render and the next render omits it, React Native hands the prop over as null, so asObject() throws Value is null, expected an Object from cloneNodeWithNewProps and the commit fails. The optional converter that would treat it as absent is never reached, and it only knew undefined anyway.

Fix, two places: ReactProp::fromRawValue only unwraps { f } when the value is an object, and JSIConverter<std::optional<T>> treats null like undefined in fromJSI and canConvert. The generated setters already pass nullptr to the platform side for an empty optional. The first change alone is not enough: the null then reaches the optional converter and the same error comes back from JSIConverter<std::function>.

Test: accepts a function prop being removed on a later render in apps/example/__tests__/nitro.views.harness.tsx. It needed an optional function prop on TestView, so the spec gains someOptionalCallback?: () => void and hasSomeOptionalCallback(): boolean, implemented in the Kotlin and Swift test views, nitrogen output regenerated. On a Galaxy A14 (SM-A145F, Android 15) the views harness is 9/9 with the fix. Without it the new test fails: the rerender that drops the prop never reaches the native view, so hasSomeOptionalCallback() still reports true (expected true to be false).

Seen first through VisionCamera: <Camera onPreviewStarted={fn} /> then a rerender without that prop fails its harness test reconfigures when the Camera device position prop changes with the same error. With both changes it passes.

ReactProp::fromRawValue unwrapped function props with asObject() before
anything checked for null. When a view had a function prop on one render and
the next render omits it, React Native hands the prop over as null, so the
unwrap threw 'Value is null, expected an Object' from cloneNodeWithNewProps and
the commit failed. The optional converter that would have treated the value as
absent was never reached, and it only knew undefined anyway.

Only unwrap { f } when the value is an object, and let
JSIConverter<std::optional<T>> treat null like undefined in fromJSI and
canConvert. The generated setters already pass nullptr to the platform side
for an empty optional.

Seen through VisionCamera: <Camera onPreviewStarted={fn} /> followed by a
rerender without that prop fails the harness test 'reconfigures when the
Camera device position prop changes' on a Galaxy A14 (SM-A145F, Android 15).
With this change the test passes.
TestView gains an optional someOptionalCallback prop and a
hasSomeOptionalCallback() method so the harness can check what the native
view received. Kotlin and Swift test views implement both. Nitrogen output
regenerated.

The new test renders TestView with the callback, rerenders without it and
expects hasSomeOptionalCallback() to be false. On a Galaxy A14 (SM-A145F,
Android 15) it fails without the ReactProp and optional converter changes
and passes with them, views harness 9/9.
@vercel

vercel Bot commented Oct 2, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated
nitro-docs Skipped Skipped Oct 2, 2026 10:02pm UTC

Request Review

This branch was previously deployed

1 inactive deployment
Preview — b944456a Deployed Oct 2, 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