Search code examples
react-nativeandroid-animationreact-native-animatable

Style property 'width' is not supported by native animated module: need advice for rewriting my code


I inherited the following component which worked well with former versions of react-native, displaying an opaque scrolling progress bar on buttons displayed by other components.

Recently, when I upgraded to react-native 0.62.2 I got an error requesting to add useNativeDriver. When adding it and setting it to 'yes', I got an error saying that "style property 'width' is not supported by native animated module".

When setting useNativeDriver to false I don't get an error but the animation doesn't work (at least not on android. Didn't test on iOS).

Any suggestion on how to modify the code to make it work with the newest version of react-native?

import React, { Component } from 'react';
import { Animated, Easing } from 'react-native';
import { connect } from 'react-redux';

class ProgressBar_Module extends Component {
  constructor(props) {
    super(props);

    this.state = {
      progress: 0
    }
    this.d_isMounted = false;
    this.d_initialTime = 0;
    this.d_animation_width = new Animated.Value(1);
    this.d_animation_progressTime = 3000;
  }

  componentDidMount() {
    this.d_initialTime = Date.now();
    this.d_isMounted = true;
    this.progressCount();
  }

  componentDidUpdate(prevProps) {
    if(prevProps.timerStart < this.props.timerStart) {
      this.setState({
        animation_width: new Animated.Value(1),
        animation_progressTime: 3000
      });
      this.progressCount(true)
    }
  }

  componentWillUnmount() {
    this.d_isMounted = false;
  }

  progressCount = (reset) => {
    if( reset ) {
      this.d_animation_width = new Animated.Value(1);
      this.d_animation_progressTime = 3000;
    }
    Animated.timing(this.d_animation_width, {
      toValue: 175,
      duration: this.d_animation_progressTime,
      easing: Easing.linear
    }).start(() => {
      if(this.props.timer && this.d_animation_width.__getValue() === 175) {
        this.props.onPress();
      }
    })
  }

  render() {

    return (
      <Animated.View
        style={[
          {
            position: 'absolute',
            left: 0,
            height: '150%',
            width: 0,
            zIndex: 1,
            backgroundColor: 'black',
          },
          { width: this.props.timer !== false ?
              this.d_animation_width : 175 }
        ]}
        onPress={this.props.onPress}
      >
      </Animated.View>
    )
  }
}

const mapStateToProps = state => {
  return {
    timer: state.get('ui').get('timer').get('timer'),
    reset: state.get('ui').get('resetTimer').get('resetTimer'),
    timerStart: state.get('ui').get('resetTimer').get('timerStart')
  }
};

export const ProgressBar = connect(mapStateToProps)(ProgressBar_Module);

Solution

  • Instead of animating the width, try using transform and scaleX. Here is some reference to react native transforms: https://reactnative.dev/docs/transforms