React-native-reanimated: Animating SVGs with reanimated are not native animations

Created on 4 Jan 2020  路  6Comments  路  Source: software-mansion/react-native-reanimated

I have noticed that when I use this library to perform animations on svgs from react-native-svg, the animations are all occurring on the javascript thread. I have included a basic snippet of animating a Circle using both reanimated and core animated library, you will notice there is no communication across the bridge for the core animated version, but many for the reanimated version.

import { View, Button, Animated as RNAnimated } from 'react-native';
import Animated, { Easing } from 'react-native-reanimated';
import Svg, { Circle } from 'react-native-svg';
import React from 'react';

const AnimatedCircle = Animated.createAnimatedComponent(Circle);
const AnimatedCircleRN = RNAnimated.createAnimatedComponent(Circle);

export default function App() {
  const transX = React.useRef(new Animated.Value(0));
  const transXRN = React.useRef(new RNAnimated.Value(0));

  const anim = Animated.timing(transX.current, {
    duration: 2000,
    toValue: 1,
    easing: Easing.inOut(Easing.ease),
  });

  const animRN = RNAnimated.timing(transXRN.current, {
    duration: 2000,
    toValue: 1,
    useNativeDriver: true,
  });

  const translateX = Animated.interpolate(transX.current, {
    inputRange: [0, 1],
    outputRange: [20, 200],
  });

  const translateXRN = transXRN.current.interpolate({
    inputRange: [0, 1],
    outputRange: [20, 200],
  });

  return (
    <View style={{ flex: 1, justifyContent: 'center' }}>
      <Svg width="300" height="100">
        <AnimatedCircle fill="red" r="50" y={50} cx={translateX} />
      </Svg>

      <Button title="Animated With Reanimated" onPress={() => anim.start()} />

      <Svg width="300" height="100">
        <AnimatedCircleRN fill="red" r="50" y={50} cx={translateXRN} />
      </Svg>

      <Button title="Animated with core React Native" onPress={() => animRN.start()} />
    </View>
  );
}

Most helpful comment

Looks like the undocumented addWhitelistedNativeProps solves this issue.

Animated.addWhitelistedNativeProps({ cx: true }); will ensure that this animated value is not sent back as a prop update to JS.

All 6 comments

Is there a way we can track an Animated.value from reanimated to an Animated.Value from core react native?

Since the SVG animations are all native on core Animated lib, but could be locked into an Animated.Value from an external library, it would be good to have these synchronised so we can have svg animations done natively.

Reanimated produces lots of calls through the bridge, but not for updating views, but in order to create and execute native driven animations.

In your example, you are not caching all the animated values and timings and might recreate them on every render.

You can see all the calls by adding this snippet to your index.js file:

import MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue.js';

let count = 0;
const spyFunction = msg => {
  if (msg.module === 'ReanimatedModule') {
    console.log(++count, msg);
  }
};

MessageQueue.spy(spyFunction);

But you should notice after you start the animation, it should not produce any additional calls (if you don't rerender your component).

Hey @terrysahaidak, I am using react native snoopy to do the same, which is just an extension of this bridge logger snippet you provided, in this example I am not caching the animated values as I dont need to as the App component will never re-render, so when triggering the Reanimated animation I see many
updateView calls over the bridge

JS->N : UIManager.updateView([3,"RNSVGCircle",{"cx":197.5465230261497}]) *

So I am unsure its an issue with how I have setup the Animated SVGs, if its a memoization issue, I have not been able to solve this.

createAnimated component from this package is updating the views
https://github.com/software-mansion/react-native-reanimated/blob/ad41f5fc5b8eee584f480a692a6df2e0513d7d22/src/createAnimatedComponent.js#L167-L173

Or if its a react-native-svg issue with how those are updated, based on reanimated node values.

So the issue seems to be that the react native svg props are not inferred as nativeProps so when they are updated on the native side for ios

https://github.com/software-mansion/react-native-reanimated/blob/8c0fc3f20bc7b6e1f9802b87a4918238db98054e/ios/Nodes/REAPropsNode.m#L67-L82

They will update on the native side, then trigger an event to update the values on the JS side onReanimatedPropsChange, which will then trigger a updateView message across the bridge to then update tme native side.

for this particular issue If I change theif (jsProps.count > 0) conditional to then update the nativeProps rather than emit the event back to JS, then this solves the issue shown above.

[self.nodesManager enqueueUpdateViewOnNativeThread:_connectedViewTag viewName:_connectedViewName nativeProps:jsProps];

So to solve the SVG animations issues then you would need to directly set the nativeProps.

Looks like the undocumented addWhitelistedNativeProps solves this issue.

Animated.addWhitelistedNativeProps({ cx: true }); will ensure that this animated value is not sent back as a prop update to JS.

Was this page helpful?
0 / 5 - 0 ratings