我一直遇到这个问题,我在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()
不会触发答案 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;
注意:如果像我一样,你使用的是turbolinks和rails,你可能想要同时关注beforeunload
和turbolinks: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()
方法来触发。数据将在上层组件中准备好,因此您可以在子组件中使用它。