question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AnimatedStop error when animating offset via AnimatedProps

See original GitHub issue

Description

If you try to animated the offset with ‘animatedProps’ on a Stop component from ‘react-native-svg’ created withAnimated.createAnimatedComponent an error appears.

Screenshots

Steps To Reproduce

  1. create a PanGesture with the sliderComponent inside and a cursor
 export const SliderComponent: React.FC<{}> = ({}) => {
  const translateX = useSharedValue<number>(0)

  const gestureHandler = useAnimatedGestureHandler<
    PanGestureHandlerGestureEvent,
    { offsetX: number }
  >({
    onActive: ({ translationX }, context) => {
      translateX.value = clamp(
        translationX + context.offsetX,
        0,
        width - HORIZONTAL_PADDING * 2,
      )
    },
    onStart: (_event, context) => {
      context.offsetX = translateX.value
    },
  })

  const animatedStyle = useAnimatedStyle(() => {
    return {
      transform: [{ translateX: translateX.value }],
    }
  })

  return (
    <View style={styles.container}>
      <PanGestureHandler onGestureEvent={gestureHandler}>
        <Animated.View>
          <Cursor />
          <Slider offset={translateX} />
        </Animated.View>
      </PanGestureHandler>
    </View>
  )
}
  1. change the offset with an animatedProps
export const Slider: React.FC<SliderProps> = ({ offset }) => {
  const normalizedWidth = width - HORIZONTAL_PADDING * 2

  const props = useAnimatedProps(() => {
    return {
      offset: interpolate(
        translateX.value,
        [0, width - HORIZONTAL_PADDING * 2],
        [0, 1],
      ),
    }
  })

  return (
    <View style={styles.container}>
      <Svg
        width={normalizedWidth}
        height="11"
        viewBox={`0 0 ${normalizedWidth + 3} 11`}
        fill="none">
        <Rect
          x="1"
          y="1"
          width={`${normalizedWidth}`}
          height="9"
          rx="4.5"
          fill="url(#paint0_linear)"
          stroke="white"
          strokeWidth="2"
          strokeLinejoin="bevel"
        />
        <Defs>
          <LinearGradient
            id="paint0_linear"
            x1="0"
            y1="6.00015"
            x2={`${normalizedWidth}`}
            y2="6.00023"
            gradientUnits="userSpaceOnUse">
            <AnimatedStop animatedProps={props} stopColor="#295672" />
            <AnimatedStop animatedProps={props} stopColor="#ED6464" />
          </LinearGradient>
        </Defs>
      </Svg>
    </View>
  )
}
  1. move the cursor and the error will appear

Expected behavior

Should just move the cursor and change the offset of the Stop.

Actual behavior

Exception in HostFunction: Value is undefined, expected a number

Package versions

  • React: 16.13.1
  • React Native: 0.63.1
  • React Native Reanimated: 2.0.0-rc.2
  • NodeJS: 12.18.0

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
karol-bisztygacommented, Jan 21, 2021

Ok so I got it working(I know it’s ugly but you got the idea). The biggest problem here is that SVG’s Stop component doesn’t render anything(renders null) so you can’t really update its props on the UI thread since it has no nativeTag(it doesn’t exist in the UI structure). As a workaround, I modified its parent’s props instead(you can try to return something like <View></View> from the Stop component and get it working somehow but you would have to force the SVG’s authors to include this change in their repo).

Your code had some bugs btw, but nevermind, you can play with the code I posted below and make it work in a way you want.

Thanks for pointing this out after all. I’m going to push a change that will make this error more clear.

code
import React from 'react';
import { StyleSheet, View } from 'react-native';
import Animated, {
  useSharedValue,
  useAnimatedProps,
  useAnimatedGestureHandler,
} from 'react-native-reanimated';
import Svg, { Rect, Defs, LinearGradient, Stop } from 'react-native-svg';
import { PanGestureHandler } from 'react-native-gesture-handler';

const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient);

const Slider = ({ offset }) => {
  const normalizedWidth = 200;
  const props = useAnimatedProps(
    () => {
      return {
        x1: offset.value,
      };
    },
  );

  return (
    <Animated.View style={styles.container}>
      <Svg
        width={normalizedWidth}
        height="11"
        viewBox={`0 0 ${normalizedWidth + 3} 11`}
        fill="none">
        <Rect
          x="1"
          y="1"
          width={`${normalizedWidth}`}
          height="9"
          rx="4.5"
          fill="url(#paint0_linear)"
          stroke="white"
          strokeWidth="2"
          strokeLinejoin="bevel"
        />
        <Defs>
          <AnimatedLinearGradient
            id="paint0_linear"
            x1="0"
            y1="6.00015"
            x2={`${normalizedWidth}`}
            y2="6.00023"
            animatedProps={props}
            gradientUnits="userSpaceOnUse">
            <Stop offset={0.1} stopColor="#295672" />
            <Stop offset={0.2} stopColor="#ED6464" />
          </AnimatedLinearGradient>
        </Defs>
      </Svg>
    </Animated.View>
  );
};

const SliderComponent = () => {
  const translateX = useSharedValue(0);

  const gestureHandler = useAnimatedGestureHandler({
    onActive: ({ translationX }, context) => {
      translateX.value = translationX + context.offsetX;
    },
    onStart: (_event, context) => {
      context.offsetX = translateX.value;
    },
  });

  return (
    <View style={[styles.container, { margin: 100 }]}>
      <PanGestureHandler onGestureEvent={gestureHandler}>
        <Animated.View>
          <Slider offset={translateX} />
        </Animated.View>
      </PanGestureHandler>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    width: 100,
    height: 100,
    backgroundColor: 'purple',
  },
});

export default SliderComponent;

0reactions
nicoache1commented, Jan 20, 2021

animated props works on an Animated component I guess. can you try making your slider component animated

const AnimatedSlider = Animated.createAnimatedComponent(Slider)

you can check this stackoverflow on how to use your functional component as animated component

Yeah I read that but, it should only be the LinearGradient component from de SVG right? I see the examples in the library with Path, G, etc.

Read more comments on GitHub >

github_iconTop Results From Across the Web

React Native Animated Listener not triggered when offset is ...
I am listening for updates to this animation to coordinate with another but it's not being triggered when the offset is updated. imagePosition....
Read more >
Animations | React Native Reanimated - Software Mansion
Animations are first-class citizens in Reanimated 2. ... The offset value is then mapped to a view translation using useAnimatedStyle .
Read more >
Animated - React Native
The Animated library is designed to make animations fluid, powerful, ... You can combine two animated values via addition, subtraction, ...
Read more >
Fixed issues in Animate release - Adobe Support
[winOS] Your Adobe Flash Player version is too old error on running ... Animate crashes on using envelope transformation multiple times on a ......
Read more >
Animations in React Native: Performance and Reason-about ...
Animated Props. Things keep getting better. Reanimated allows us to animate arbitrary props on the UI thread via a useAnimatedProps hook. From ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found