microsoft / microsoft/react-native-windows

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

Open
#3,460 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Area: Animation bug Partner: Facebook Partner: Xbox Workstream: Component Parity
Dominant language
C++
Stars
17.3k
Forks
1.2k
Avg merge
1d 13h
Merged PRs (30d)
33

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the JavaScript repro using Animated.View and Animated.timing with useNativeDriver, and trace how removing the animated transform or opacity from the style is handled on Windows. Done means the previously applied transform or opacity resets when the value is no longer present, with the supplied toggle scenario no longer leaving the view translated.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react
Domain
desktop, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.