React,两个组件运行两个超时来卸载;相同的卸载两次被调用

时间:2018-06-26 02:35:46

标签: javascript reactjs

TL; DR :这种情况正在发生:https://jsfiddle.net/69z2wepo/204124/ 为什么它们都同时消失?应该只应用于一个组件的样式似乎同时应用于两个组件。

此版本:https://jsfiddle.net/69z2wepo/204131/的颜色变为红色而不是改变不透明度,使问题更加清楚;即使超时仅设置为一个,红色样式也会应用于这两个通知。

在安装Notification组件时,它将为可变延迟设置超时:

componentDidMount = () => {
        let timeout = parseInt(this.props.decay) || 2000
        this.setState({ 
            dismissTimeout: setTimeout(() => {
                this.fadeOutFunction();
                setTimeout(() => {
                    this.dismiss();
                }, 125)
            }, timeout)
        })  
    }   
}

淡出动画将在100毫秒内发生,然后将组件卸下:

fadeOutFunction = () => {
    let opacity = Math.floor(this.state.style.opacity * 10) 
    if ( opacity > 0) {
        opacity -= 1;  
        setTimeout(() => { this.fadeOutFunction() }, 10) 
    }   
    let newState = Object.assign({}, this.state.style)
    newState.opacity = opacity / 10
    this.setState({ style: newState })
} 

dismiss函数与父组件中的此函数挂钩,该父组件正在管理Notification组件的数据“模型”数组:

dismiss = () => {
    this.props.dismiss(this.props.code);
} 

// in parent
dismissNotification = (code) => {
    this.setState({ notifications: this.state.notifications.filter (
        n => n.code != code
    )})
} 

设置了两个通知,一个带有2000衰减的通知,另一个带有5000衰减的通知。

当第一个组件结束淡出时,会发生一些非常奇怪的行为;两个组件都失去了不透明性(设置为0),并且对错误的组件调用了dismount函数……疯狂的是,fadeOut函数继续调用“ dismount”组件(5000ms,仍在DOM中) )导致错误:

Warning: Can't call setState (or forceUpdate) on an unmounted component.

但是真正令我困惑的是,如果我检查dismissNotification,它将过滤出正确的通知。

更新:jsFiddle现在重现错误: https://jsfiddle.net/69z2wepo/204124/

但是没有任何问题!看我的代码,我认为没有任何明显的区别,实际上,当我更改fadeOut函数改为“将组件设置为红色”时:

makeRedFunction = () => {
    this.setState({ style: {backgroundColor: "red"} })
}

这些组件会在适当的时间更改其样式,并正确无误地关闭它们。

对不起,这有点含糊:/并且我真的希望我知道如何获取更多正确的信息,但是..为什么设置不透明度不会在codefiddle上触发错误却在我的应用程序中触发一个错误?为什么不透明度会导致这种奇怪的跨组件行为,而颜色却没有?

我在项目中缺少一些对动画至关重要的依赖吗?我已经看到有动画库,但是用这些简单的东西我只想自己编写即可。

**编辑:** 我的父组件的渲染

            {
                this.state.notifications.map( (n, idx) => {                                                                                                                       
                    return <Notification                                                                                                                                          
                        key={idx}                                                                                                                                                 
                        code={n.code}                                                                                                                                             
                        decay={n.decay}
                        dismiss={ () =>{this.dismissNotification(n.code)}}                                                                                                                        
                    > 
                        { n.message }                                                                                                                                             
                    </Notification>                                                                                                                                               
                })                                                                                                                                                                
            } 

1 个答案:

答案 0 :(得分:0)

这是通知组件中的逻辑错误:

setTimeout(() => {
  this.fadeOutFunction();
  setTimeout(() => {  // <--- This part is uneccessary
   this.dismiss();
  }, 125)
}, timeout)     

将其更改为:

class Notification extends React.Component {
    constructor(props) {
    super(props)
    this.state = {
        style: { opacity: 1 }
    }
  }

  componentDidMount = () => {
    let timeout = parseInt(this.props.decay) || 2000

    setTimeout(() => {
      this.fadeOutFunction();
    }, timeout)     
  }

  fadeOutFunction = () => {
    let opacity = Math.floor(this.state.style.opacity * 10)
    if (opacity > 0) {
        opacity -= 1
      setTimeout( () => { this.fadeOutFunction() }, 10)
    }
    let newState = Object.assign({}, this.state.style)
    newState.opacity = opacity / 10
    this.setState({ style: newState })
  }

  dismiss = () => {
    this.props.dismiss(this.props.code)
  }

  render () {
    return(
         <div style={this.state.style}>{this.props.children}</div>
    )
  }
}