Skip to content

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

Open
@Thristhart

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>
    </>
  );
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions