While upgrading our app to RN 0.86.0 and bumping Reanimated from 4.2.2 to 4.4.1 some animated components started crashing the app. Specifically components animating props belonging to Shopify Restyle's theming, like borderRadius or zIndex. It seems the culprit its also a source of Reanimated performance improvements, which is one of the reasons we want to upgrade, so it would not be ideal to turn it off. Upon quite a bit of debugging with Claude this is the information I gathered:
When a theme-key prop (borderRadius, zIndex, spacing props, etc.) receives a value that is not a key in the corresponding theme scale, getThemeValue throws a hard error — even when the value is a valid literal style value such as a raw pixel number. This makes restyle stricter than peer theme-prop libraries (styled-system, dripsy), which pass unknown values through, and it turns benign upstream behavior into render crashes.
Current behavior
if (isThemeKey(theme, themeKey)) {
if (value && theme[themeKey][value] === undefined)
throw new Error(`Value '${value}' does not exist in theme['${String(themeKey)}']`);
return value ? theme[themeKey][value] : value;
}
Any truthy value that is not a theme key throws, regardless of whether it is a number (a legitimate literal) or a string (likely a typo).
react-native-reanimated 4.4.x ships a default-on feature flag FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS, which - when an animation settles - spreads the
resolved animated style values onto the wrapped component as top-level props (in addition to style). When that wrapped component is a restyle createBox()/AnimatedBox, the settled numeric values arrive as theme-key props:
Value '13' does not exist in theme['borderRadii'] // animated borderRadius
Value '1' does not exist in theme['zIndices'] // animated zIndex
Expected behavior
A numeric value passed to a theme-key prop should be treated as a literal style value and passed through (this is how styled-system and dripsy behave), rather than throwing. Strings that are not theme keys are the genuine typo case and could still throw or warn. In short:
- borderRadius="m" and not a key -> likely a typo, throw/warn (current behavior, fine).
- borderRadius={13} -> a literal value, pass it through.
A passthrough-for-numbers default, or at minimum a configurable option, would restore compatibility without losing typo detection.
Also just leaving my thanks to the Shopify Restyle team, as I think this is the first problem we have encountered in 4 years of using the library.
To Reproduce
const ButtonContainer = createRestyleComponent<
VariantProps<Theme, 'buttonVariants'> & React.ComponentProps<typeof Box>,
Theme
>(restyleFunctions, Box);
const AnimatedButtonContainer = Animated.createAnimatedComponent(ButtonContainer);
const { borderRadii } = useTheme<Theme>();
const animatedContainerStyle = useAnimatedStyle(() => {
if (!containerWidth.value || !circularLoading) {
return {};
}
const borderRadius = interpolate(loadingProgress.value, [0, 1], [borderRadii.base, borderRadii.xxl]);
return {
height: circleSize,
borderRadius,
};
});
<AnimatedButtonContainer
style={animatedContainerStyle}
}>
{renderContentBox()}
</AnimatedButtonContainer>;
Platform:
Environment
2.4.5
While upgrading our app to RN 0.86.0 and bumping Reanimated from 4.2.2 to 4.4.1 some animated components started crashing the app. Specifically components animating props belonging to Shopify Restyle's theming, like borderRadius or zIndex. It seems the culprit its also a source of Reanimated performance improvements, which is one of the reasons we want to upgrade, so it would not be ideal to turn it off. Upon quite a bit of debugging with Claude this is the information I gathered:
When a theme-key prop (borderRadius, zIndex, spacing props, etc.) receives a value that is not a key in the corresponding theme scale, getThemeValue throws a hard error — even when the value is a valid literal style value such as a raw pixel number. This makes restyle stricter than peer theme-prop libraries (styled-system, dripsy), which pass unknown values through, and it turns benign upstream behavior into render crashes.
Current behavior
Any truthy value that is not a theme key throws, regardless of whether it is a number (a legitimate literal) or a string (likely a typo).
react-native-reanimated 4.4.x ships a default-on feature flag FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS, which - when an animation settles - spreads the
resolved animated style values onto the wrapped component as top-level props (in addition to style). When that wrapped component is a restyle createBox()/AnimatedBox, the settled numeric values arrive as theme-key props:
Value '13' does not exist in theme['borderRadii'] // animated borderRadius
Value '1' does not exist in theme['zIndices'] // animated zIndex
Expected behavior
A numeric value passed to a theme-key prop should be treated as a literal style value and passed through (this is how styled-system and dripsy behave), rather than throwing. Strings that are not theme keys are the genuine typo case and could still throw or warn. In short:
A passthrough-for-numbers default, or at minimum a configurable option, would restore compatibility without losing typo detection.
Also just leaving my thanks to the Shopify Restyle team, as I think this is the first problem we have encountered in 4 years of using the library.
To Reproduce
Platform:
Environment
2.4.5