Skip to content

fix: Treat null as undefined for removed optional View props - #1515

Open
mrousavy wants to merge 1 commit into
mainfrom
fix/view-optional-prop-removal
Open

fix: Treat null as undefined for removed optional View props#1515
mrousavy wants to merge 1 commit into
mainfrom
fix/view-optional-prop-removal

Conversation

@mrousavy

@mrousavy mrousavy commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • React's Fabric diff sends an explicit null sentinel for a removed prop (ReactNativeAttributePayload: "Flag the leaf property for removal by sending a sentinel") - and prop={undefined} takes the same path, so the two are indistinguishable on the wire
  • CachedProp previously passed that null straight into conversion, which throws mid-commit for every optional prop type that rejects null (optional<double> via asNumber(), and hybridRef even earlier, in the { f } function-prop unwrap)
  • now: if the prop type is optional and null is not a valid value for it (JSIConverter<T>::canConvert), the value is normalized to undefined → the native setter is called once with nullopt

Semantics

  • optional prop removed / set to undefined → setter receives nullopt (the JS-visible value becomes undefined). The native initializer default still only covers never-provided props - a richer "reset on clear" belongs in the implementation (storage ?? default)
  • props that can legitimately hold null (NullType, variants containing null): untouched - null stays data, so removal collapses to "explicit null" for those (inherent to React's sentinel protocol)
  • required props: unchanged, removal still throws loudly with the ViewName.propName: prefix

Because normalization only applies where conversion was guaranteed to throw, no currently-working behavior can change.

Overhead

  • non-optional props: none - the if constexpr (is_optional<T>) branch compiles out
  • optional props: one value.isNull() tag check during Props parsing; the canConvert walk only runs when the value actually is null (i.e. an actual removal)

Testing

New Harness test delivers undefined when an optional prop is removed": mounts TestView with nativeDefaultValue={1}+hybridRef, then removes both - asserts the value reads undefined, the setter fired exactly once more, unrelated setters (isBlue) did not fire, and the previously-crashing hybridRef` removal path survives. Red without the fix (commit-time throw), green with it.

Validated: workspace typecheck, eslint (CI settings), clang-format.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
nitro-docs Skipped Skipped Aug 21, 2026 10:11am

Request Review

React Fabric diff turns a removed prop into an explicit null sentinel (and prop={undefined} takes the same path). Nitro ReactProp passed that null straight to JSIConverter, which throws for non-null types, so removing any previously-provided optional View prop (including hybridRef, which crashed earlier in the { f } unwrap) failed the Fabric commit.

Now, if the prop type is optional and null is not a valid value for it (checked via JSIConverter<T>::canConvert), the value is normalized to undefined and the setter is called once with nullopt. Props that can legitimately hold null (NullType, variants containing null) are untouched, and required props still throw loudly. Zero overhead for non-optional props (the branch compiles out), one isNull() tag check for optional ones.
@mrousavy
mrousavy force-pushed the fix/view-optional-prop-removal branch from 737d1c7 to 089bc77 Compare August 21, 2026 10:11
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.

Error when assigning undefined to optional view property

1 participant