Skip to content

withUniwind + Reanimated #529

@Alvi24

Description

@Alvi24

withUniwind wraps the style prop into a plain array, breaking Reanimated 4 AnimatedStyleHandle propagation

Repro link: https://stackblitz.com/edit/vitejs-vite-qg3b19nm?file=reproduction.ts

uniwind: 1.6.4
react-native-reanimated: ~4.3.1
react-native-svg: (latest)
Expo 54 / React Native (New Architecture)

In withUniwind.native.tsx, withManualUniwind merges the className-generated styles with the incoming style prop by creating a plain JS array:

// withUniwind.native.tsx — withManualUniwind, lines 121-127
const existingStyle = props[propName] // AnimatedStyleHandle from useAnimatedStyle

if (existingStyle) {
acc.generatedProps[propName] = [styles, existingStyle] // ← plain array wrapping
return acc
}
This plain array is then spread onto the wrapped component:

<Component {...props} {...generatedProps} />
// Component receives: style={[{ color: '...' }, AnimatedStyleHandle]}
Reanimated 4 does not scan plain arrays recursively for AnimatedStyleHandle instances. It only recognises an AnimatedStyleHandle when it is the direct value of the style prop, not when it is nested inside a plain array. As a result:

The animated handle is effectively dead — Reanimated cannot attach the UI-thread animation to the underlying native view.
The style updates only happen when React reconciles (e.g., at the moment the animation is triggered, not per-frame), producing an instantaneous snap instead of a smooth transition.
Minimal reproduction

import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
import { Svg } from 'react-native-svg';
import { withUniwind } from 'uniwind';

const AnimatedSvg = Animated.createAnimatedComponent(Svg);
const StyledSvg = withUniwind(AnimatedSvg, {
style: { fromClassName: 'className' },
});

function Example() {
const progress = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => ({
opacity: progress.value,
}));

// animatedStyle is an AnimatedStyleHandle.
// withUniwind wraps it into [generatedStyles, AnimatedStyleHandle].
// Reanimated doesn't recognise the handle inside the array → no smooth animation.
return ;
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions