如何使用componentWillUnmount停止循环动画?

时间:2019-06-04 07:57:06

标签: reactjs react-native

我有一个页面,其中包含不同的组件,其中一个组件中具有循环动画,我将在安装子组件时启动动画。当我切换到另一个屏幕时,我想停止动画。因此,我尝试停止在componentWillUnmount生命周期中包含一个组件的动画,该动画将运行我的stop函数,但是此后,它将再次运行动画,并且我不知道如何停止它。

实际上,我想确保内存安全,我希望动画仅在安装此组件时开始,而在卸载时停止。

这是我的第一个包含动画子组件(StoreBoxItems)的组件:

export class StoreBoxPackages extends Component {
  render() {
    const {    
      onPress,
      packTitle,
      currency,      
      discount,      
      items,
      price,
      packageType,
      keyIndex,
      packID,      
    } = this.props;
    //let b = [];
    let rows = []
    let itemsNumber = 0; 
    if (items != null){
      //console.log('ssssxxxx')
      itemsNumber = items.length; 
    }
    //console.log('itemsNumber', itemsNumber)   
    let rowsNumber = Math.ceil(itemsNumber/3);
    //console.log('rowNum' , rowsNumber)
    let boxIndex = 0;
    for(let i = 1; i <= rowsNumber; i++){
      let row = [];
      for(let j = 0; j< 3 && boxIndex<itemsNumber; j++,boxIndex++){               
          row.push(
            <StoreBoxItems
              stateKey={`${i}${j}`}
              price={price}
              currency={currency} 
              unit={items[boxIndex].unit}
              type={items[boxIndex].type}
              titleColor={items[boxIndex].caption_color}
              duration={items[boxIndex].duration}
              ientifier={items[boxIndex].identifier}
              asset_id={items[boxIndex].asset_id}
              packageType={packageType}
              caption={items[boxIndex].caption}
              itemID={packID}
              onPress={onPress}
            />
          )
          if(boxIndex + 1 == itemsNumber && itemsNumber > 3){
              let reminder = itemsNumber % 3;              
              let moreBox = 3 - reminder;
              //console.log('boxIndex', boxIndex ,'itemsNumber', itemsNumber, 'reminder', reminder , 'moreBox', moreBox)
              if(reminder != 0 && moreBox > 0){
                 for(let k=0;k<moreBox;k++){
                   row.push(<View style={{flex : 1}}></View>) 
                 } 
              }
          }               
      }
      rows.push(
        <View key={makeid(8)} style={{flexDirection: 'row', flexGrow: 1, alignItems: 'center', justifyContent: 'space-around' }}>
            {row}          
        </View>
      )
    }    
      return (
        <View key={makeid(8)} style={{flexGrow: 1}}>          
            {rows} 
          <View>
            {packageType == 'COLLECTION' ?
            <StoreBoxItemsBtn
              price={price}
              currency={currency}
              itemID={packID}
              onPress={onPress}
            />
            : null }
          </View>
        </View>                  
      );    
  }
}

这是我的孩子动画组件(StoreBoxItems)

export class StoreBoxItems extends Component {
  constructor(props) {
    super(props);
    this.state = {
      progress: new Animated.Value(0),
      appState: AppState.currentState
    };
    this.backColor = '#201F3F';
    this.runAnimationSate = true;
  }

  componentWillMount(){
    //this._chackBackColor()
    this.runAnimation();
  }

  componentDidMount() {
    AppState.addEventListener("change", this._handleAppStateChange); 
  }

  componentWillUnmount(){
    AppState.removeEventListener("change", this._handleAppStateChange);
    console.log('unmonted anime');
    this.runAnimationSate = false;
    Animated.timing(this.state.progress).stop();
    //Animated.loop(Animated.timing(this.state.progress)).stop();  
  }

  runAnimation() {
    console.log('run animation');
    this.state.progress.setValue(0);
    Animated.timing(this.state.progress, {
      toValue: 1,
      duration: 3000,
      easing: Easing.linear,
      useNativeDriver : true
    })
    .start(() => {
        if (this.runAnimationSate) {
            this.runAnimation();
        }
    })
}

  _handleAppStateChange = (nextAppState) => {
    if (this.state.appState.match(/inactive|background/) && nextAppState === "active"){
      console.log('active')
      this.runAnimation();
    }else{
      console.log('DEactive')      
        Animated.timing(this.state.progress).stop();
        this.setState({appState: nextAppState});
  }
}

  render() {
    const {
      stateKey,    
      price,
      currency,
      caption,
      unit,
      type,
      duration,
      ientifier,
      asset_id,
      titleColor,
      packageType,
      itemID,
      onPress
    } = this.props; 
    let itemHeader = '';
    let xduration = 0;
    switch (type) {
      case "BOOSTER" :
      xduration =  (duration / 3600);
      if(xduration >= 1){
        itemHeader = `${xduration} H, ${ientifier}x`;
      }else{
        xduration =  (duration / 60);
        itemHeader = `${xduration} Min, ${ientifier}x`;
      }

      break;
      case "COIN" :
      itemHeader = unit;
      break;
      default :
      itemHeader = unit;
      break;
   }
      return (
        <View key={makeid(8)} style={[styles.boxItems]}>
          <View style={[styles.boxItemIconHolder,{backgroundColor : this.backColor}]}>
            <Text style={[{color : titleColor}, globalStyles.mediumFont, globalStyles.acmeFont]}>{itemHeader}</Text>
            <Image
              source={icons[asset_id]}
              style={{ width: normalize(40), height: normalize(40), marginTop: 2 }}
            />
            {type == "COIN" ?
            <LottieView
              style={{               
                position: 'absolute',
                height: 30,
                width: 30,
                zIndex:1
              }}
                progress={this.state.progress}              
                source={lotties['shineBox']}
                loop={true}                            
                //autoPlay={true}
            />
            : null }
          </View>
          <Text style={[globalStyles.lightColor, globalStyles.mediumFont, globalStyles.acmeFont, styles.boxItemTitle]}>{caption}</Text>
          {packageType == 'ITEM' ?
          <StoreBoxItemsBtn
            price={price}
            currency={currency} 
            itemID={itemID}
            onPress={onPress}
          />
          : null }
        </View>           
      );    
  }
}

2 个答案:

答案 0 :(得分:1)

这很奇怪,因为您似乎已经正确执行了,是否尝试过this.state.progress.stopAnimation()?

此外,我的建议是do not put animated value into state

  

状态值在React和React Native中用于动态更新   一个组件。这意味着该组件的render()方法是   每次状态更新时调用。

     

现在您可能会认为,由于组件已更新   动态地,可以将动画值存储在状态中。

     

假设我们已将动画滚动事件映射到状态。依此类推   每次滚动时,都会调用render方法,从而导致   不必要的开销。因此,如果我们在屏幕上滚动700像素,   方法已更新700次。

答案 1 :(得分:0)

那是因为我正在使用reactnavigation,发现我需要使用它的lifeCycle而不是react componentWillUnmount。 在我的情况下,我为willBlur状态及其运行状况添加了一个监听器,

https://reactnavigation.org/docs/en/navigation-lifecycle.html

相关问题