刷新当前页面时未调用componentWillUnmount()

时间:2016-08-22 16:57:04

标签: reactjs

我一直遇到这个问题,我在componentDidMount()方法中的代码在刷新当前页面(以及随后的组件)时没有正确触发。但是,它通过单击链接在我的网站上导航和路由完美地工作。刷新当前页面?没机会。

我发现问题在于,当我刷新页面并触发精细点击链接并浏览我的网站/应用时,componentWillUnmount()不会触发。

触发componentWillUnmount()对我的应用至关重要,因为我在componentDidMount()方法中加载和处理的数据对于向用户显示信息非常重要。

我需要在刷新页面时调用componentWillUnmount(),因为在我的componentWillMount()函数中(每次刷新后需要重新渲染)我做了一些简单的过滤并将该变量存储在一个状态中value,需要出现在logos状态变量中,以便组件的其余部分工作。在组件的生命周期中,这不会随时更改或接收新值。

componentWillMount(){
  if(dataReady.get(true)){
    let logos = this.props.questions[0].data.logos.length > 0 ? this.props.questions[0].data.logos.filter((item) => {
      if(item.logo === true && item.location !== ""){
        return item;
      }
    }) : [];
    this.setState({logos: logos});
  }
};

悬崖:

  • 我在componentWillMount()方法
  • 中进行数据库过滤
  • 刷新后需要它出现在组件中
  • 但我有一个问题,当页面刷新时componentWillUnmount()不会触发
  • 需要帮助

3 个答案:

答案 0 :(得分:40)

当页面刷新时,反应没有机会正常卸载组件。使用window.onbeforeunload事件设置刷新处理程序(读取代码中的注释):

class Demo extends React.Component {
    constructor(props, context) {
        super(props, context);

        this.componentCleanup = this.componentCleanup.bind(this);
    }

    componentCleanup() { // this will hold the cleanup code
        // whatever you want to do when the component is unmounted or page refreshes
    }

    componentWillMount(){
      if(dataReady.get(true)){
        let logos = this.props.questions[0].data.logos.length > 0 ? this.props.questions[0].data.logos.filter((item) => {
          if(item.logo === true && item.location !== ""){
            return item;
          }
        }) : [];

        this.setState({ logos });
      }
    }

    componentDidMount(){
      window.addEventListener('beforeunload', this.componentCleanup);
    }

    componentWillUnmount() {
        this.componentCleanup();
        window.removeEventListener('beforeunload', this.componentCleanup); // remove the event handler for normal unmounting
    }

}

答案 1 :(得分:7)

我也遇到了这个问题,并意识到我需要确保至少2个组件始终优雅地卸载。所以我最终做了一个高阶组件,确保包装的组件始终是卸载的



import React, {Component} from 'react'

// this high order component will ensure that the Wrapped Component
// will always be unmounted, even if React does not have the time to
// call componentWillUnmount function
export default function withGracefulUnmount(WrappedComponent) {

    return class extends Component {

        constructor(props){
            super(props);
            this.state = { mounted: false };
            this.componentGracefulUnmount = this.componentGracefulUnmount.bind(this)
        }


        componentGracefulUnmount(){
            this.setState({mounted: false});

            window.removeEventListener('beforeunload', this.componentGracefulUnmount);
        }

        componentWillMount(){
            this.setState({mounted: true})
        }

        componentDidMount(){
            // make sure the componentWillUnmount of the wrapped instance is executed even if React
            // does not have the time to unmount properly. we achieve that by
            // * hooking on beforeunload for normal page browsing
            // * hooking on turbolinks:before-render for turbolinks page browsing
            window.addEventListener('beforeunload', this.componentGracefulUnmount);
        }

        componentWillUnmount(){
            this.componentGracefulUnmount()
        }

        render(){

            let { mounted }  = this.state;

            if (mounted) {
                return <WrappedComponent {...this.props} />
            } else {
                return null // force the unmount
            }
        }
    }

}
&#13;
&#13;
&#13;

注意:如果像我一样,你使用的是turbolinks和rails,你可能想要同时关注beforeunloadturbolinks:before-render事件。

答案 2 :(得分:0)

我看到这个问题有超过一千个观点,所以我将解释我是如何解决这个问题的:

要解决此特定问题,最明智的方法是创建一个加载订阅或数据库的上层组件,以便在将所需数据传递给子组件之前加载所需的数据,这将完全消除使用的需要componentWillMount()。此外,您可以在上层组件中进行计算,然后将它们作为道具传递给您在接收组件中使用

例如:

class UpperLevelComponent extends React.Component {

render() {
if(this.props.isReady) {
return(<ChildComponent {...props}/>)
}
}
}

export default createContainer(() => {
const data = Meteor.subscribe("myData");
const isReady = data.ready();

return {
isReady,
data: MyData.find.fetch()
}
})

在上面的例子中,我使用Meteor的反应容器来获取我的MongoDB数据并等待它在我渲染子组件之前完全完成订阅,并传递我想要的任何道具。如果将所有数据加载到更高级别的组件中,则每次刷新后都不必依赖componentWillMount()方法来触发。数据将在上层组件中准备好,因此您可以在子组件中使用它。