Skip to content

fix(animated): use WeakMap cache in createHost - #2558

Open
ErfanBagheri404 wants to merge 18 commits into
pmndrs:v10from
ErfanBagheri404:fix/createhost-weakmap-cache
Open

fix(animated): use WeakMap cache in createHost#2558
ErfanBagheri404 wants to merge 18 commits into
pmndrs:v10from
ErfanBagheri404:fix/createhost-weakmap-cache

Conversation

@ErfanBagheri404

Copy link
Copy Markdown

Summary

On React Native (Hermes), host components (View, Text, Image) become non-extensible after their first JSX render. createHost previously stashed the animated wrapper directly on the component:

Component[cacheKey] || (Component[cacheKey] = withAnimated(Component, hostConfig))

With Metro inlineRequires + experimentalImportSupport, @react-spring/native can first be required during a render — by which point Hermes has locked the host component shapes — so createHost threw TypeError: cannot add a new property, and Metro's guardedLoadModule swallowed it returning undefined, cascading into Cannot read property 'useSpring' of undefined.

Changes

  • Replaced the per-component Symbol.for('AnimatedComponent') property with a module-level WeakMap cache in createHost.
  • The original component is never mutated, so non-extensible host components are safe.
  • Added a regression test (createHost.test.ts) that freezes a fake host component and asserts animated() neither throws nor returns the same reference.

Test plan

  • packages/animated/src/createHost.test.ts (new)
  • Changeset: @react-spring/animated: patch

Links

@changeset-bot

changeset-bot Bot commented Aug 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4ccc219

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@react-spring/animated Patch
@react-spring/core Patch
@react-spring/mock-raf Patch
@react-spring/parallax Patch
@react-spring/rafz Patch
@react-spring/shared Patch
@react-spring/types Patch
@react-spring/three Patch
@react-spring/web Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@joshuaellis

joshuaellis commented Aug 17, 2026

Copy link
Copy Markdown
Member

WeakMap swap looks right.

CI is failing on formatting only. The else block in createHost.ts is over-indented so oxfmt fails. Run pnpm format and push.

Optional: the nested if/else can be one branch.

} else {
  let cached = animatedComponentCache.get(Component)
  if (!cached) {
    cached = withAnimated(Component, hostConfig)
    animatedComponentCache.set(Component, cached)
  }
  Component = cached
}

@ErfanBagheri404 ErfanBagheri404 changed the title fix(animated): use WeakMap cache in createHost (Hermes-safe) fix(animated): use WeakMap cache in createHost Aug 17, 2026
@ErfanBagheri404

ErfanBagheri404 commented Aug 17, 2026

Copy link
Copy Markdown
Author

Done — formatted and pushed. The else branch now uses your suggested shape (let cached + single set), and the branch is a single commit on next.

@joshuaellis
joshuaellis changed the base branch from next to v10 August 17, 2026 09:38
@joshuaellis

Copy link
Copy Markdown
Member

you targetted the wrong base branch, if you check next (without using an LLM) you'll see react-native was removed, you need to focus on the v10 branch for this imo.

@joshuaellis joshuaellis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs correct rebase target branch

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.

animated() throws 'cannot add a new property' on non-extensible React Native host components (Hermes)

5 participants