Skip to content

Native driver persists animated values after they're no longer applied #3460

Description

@thristhart

Environment

  1. react-native -v:
react-native-cli: 2.0.1
react-native: 0.60.6
  1. npm ls rnpm-plugin-windows:
rnpm-plugin-windows@0.3.7
  1. npm ls react-native-windows:
react-native-windows@0.60.0-vnext.37
  1. node -v:
v10.15.0
  1. npm -v:
6.4.1

Then, specify:

  • Target Platform Version(s): 10.0.18362
  • Target Device(s): Desktop, Xbox
  • Visual Studio Version: 2019
  • Build Configuration: Debug and Release

Steps to Reproduce

  1. Pass a style to an Animated.View that contains a transform or opacity set to an Animated.Value
  2. Use Animated.timing to animate that Animated.Value to a new value, with useNativeDriver: true
  3. Update the Animated.View such that it no longer has the Animated.Value in its styles

Expected Behavior

The transform or opacity would reset to initial values. A View translated to the right previously would have that translation removed.

Actual Behavior

The transform or opacity remain applied, even though the style no longer contains those values.

Reproducible Demo

image
image
image

import React from "react";
import { Animated, Easing, Text, TouchableOpacity } from "react-native";

export default class AnimationPersistRepro extends React.Component {
    state = { animated: false };
    translateXAnimated = new Animated.Value(0);
    onPress = () => {
        this.setState((state) => {
            const shouldAnimate = !state.animated;
            if (shouldAnimate) {
                Animated.timing(this.translateXAnimated, {
                    duration: 400,
                    toValue: 100,
                    easing: Easing.linear,
                    useNativeDriver: true,
                }).start();
            }
            return { animated: shouldAnimate };
        });
    };
    render() {
        const animatedStyle = {
            transform: [{ translateX: this.translateXAnimated }],
        };
        const nonAnimatedStyle = {
            transform: [],
        };
        return (
            <>
                <Animated.View style={this.state.animated ? animatedStyle : nonAnimatedStyle}>
                    <Text>Animates to the right</Text>
                </Animated.View>
                <TouchableOpacity onPress={this.onPress}>
                    <Text>Press to toggle animation. Currently animated: {this.state.animated.toString()} </Text>
                </TouchableOpacity>
            </>
        );
    }
}

----alternative repro as a function component-----

const AnimationPersistRepro = () => {
  const [isAnimated, setAnimated] = useState(false);
  const translateXAnimated = useRef(new Animated.Value(0));

  const animatedStyle = {
    transform: [ { translateX: translateXAnimated.current } ]
  };
  const nonAnimatedStyle = {
    transform: []
  };

  const onPress = () => {
    setAnimated(animated => {
      const shouldAnimate = !animated;
      if(shouldAnimate) {
        Animated.timing(translateXAnimated.current, {
          duration: 400,
          toValue: 100,
          easing: Easing.linear,
          useNativeDriver: true
        }).start();
      }
      return shouldAnimate;
    });
  };

  return (
    <>
      <Animated.View style={isAnimated ? animatedStyle : nonAnimatedStyle}>
        <Text>Animates to the right</Text>
      </Animated.View>
      <TouchableOpacity onPress={onPress}>
        <Text>Press to toggle animation. Currently animated: {isAnimated.toString()} </Text>
      </TouchableOpacity>
    </>
  );
};

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions