Bug
@react-spring/animated's createHost caches animated wrappers by writing directly to the component object:
Component[cacheKey] = withAnimated(Component, hostConfig)
On Hermes, React Native host components (View, Text, Image) become non-extensible after their first JSX render. In strict mode this throws TypeError: cannot add a new property, which crashes the module initialization.
Reproduction
- React Native with Hermes
- Metro config:
inlineRequires: true + experimentalImportSupport: true
- Any component that uses
@react-spring/native loaded lazily (inside a render)
With inlined requires, @react-spring/native is first required during a component render — by that point Hermes has already rendered the host components via JSX elsewhere and locked their shapes. createHost runs at module scope, iterates { View, Text, Image }, and throws on the first Component[cacheKey] = ... assignment.
Metro's guardedLoadModule swallows the error and returns undefined for the module, causing a subsequent TypeError: Cannot read property 'useSpring' of undefined.
Call stack (from device)
animated react-spring_animated.development.cjs:356
<anonymous> react-spring_animated.development.cjs:365
eachProp react-spring_shared.development.cjs:120
createHost react-spring_animated.development.cjs:361
<global> react-spring_native.development.cjs:90
loadModuleImplementation require.js:285
guardedLoadModule
Fix
Use the direct property write as the fast path, catch the TypeError, and fall back to a module-level WeakMap:
const fallbackCache = new WeakMap<object, any>()
// inside animated():
let cached = Component[cacheKey] ?? fallbackCache.get(Component)
if (!cached) {
cached = withAnimated(Component, hostConfig)
try {
Component[cacheKey] = cached
} catch {
// non-extensible component (e.g. Hermes host component)
}
fallbackCache.set(Component, cached)
}
Component = cached
PR with fix: https://github.com/AndreiCalazans/react-spring/pull/new/fix/non-extensible-component-cache
Bug
@react-spring/animated'screateHostcaches animated wrappers by writing directly to the component object:On Hermes, React Native host components (
View,Text,Image) become non-extensible after their first JSX render. In strict mode this throwsTypeError: cannot add a new property, which crashes the module initialization.Reproduction
inlineRequires: true+experimentalImportSupport: true@react-spring/nativeloaded lazily (inside a render)With inlined requires,
@react-spring/nativeis first required during a component render — by that point Hermes has already rendered the host components via JSX elsewhere and locked their shapes.createHostruns at module scope, iterates{ View, Text, Image }, and throws on the firstComponent[cacheKey] = ...assignment.Metro's
guardedLoadModuleswallows the error and returnsundefinedfor the module, causing a subsequentTypeError: Cannot read property 'useSpring' of undefined.Call stack (from device)
Fix
Use the direct property write as the fast path, catch the
TypeError, and fall back to a module-levelWeakMap:PR with fix: https://github.com/AndreiCalazans/react-spring/pull/new/fix/non-extensible-component-cache