从官方教程:
在卸载和销毁组件之前立即调用中创建的任何DOM元素
componentWillUnmount()
。在此方法中执行任何必要的清理,例如使计时器无效,取消网络请求或清除在componentDidMount
我理解“使计时器无效”。可以使用fetch
中止AbortController
。但我不明白“清理componentDidMount
中创建的任何DOM元素”,我能看到这种情况的例子吗?
答案 0 :(得分:29)
如果网络请求发送库支持中止正在进行的网络请求调用,您肯定可以用componentWillUnmount
方法调用它。
然而,关于清理DOM
元素的问题令人担忧。根据我目前的经验,我将举几个例子。
第一个是 -
import React, { Component } from 'react';
export default class SideMenu extends Component {
constructor(props) {
super(props);
this.state = {
};
this.openMenu = this.openMenu.bind(this);
this.closeMenu = this.closeMenu.bind(this);
}
componentDidMount() {
document.addEventListener("click", this.closeMenu);
}
componentWillUnmount() {
document.removeEventListener("click", this.closeMenu);
}
openMenu() {
}
closeMenu() {
}
render() {
return (
<div>
<a
href = "javascript:void(0)"
className = "closebtn"
onClick = {this.closeMenu}
>
×
</a>
<div>
Some other structure
</div>
</div>
);
}
}
这里我删除了在安装组件时添加的click事件监听器。
第二个是 -
import React from 'react';
import { Component } from 'react';
import ReactDom from 'react-dom';
import d3Chart from './d3charts';
export default class Chart extends Component {
static propTypes = {
data: React.PropTypes.array,
domain: React.PropTypes.object
};
constructor(props){
super(props);
}
componentDidMount(){
let el = ReactDom.findDOMNode(this);
d3Chart.create(el, {
width: '100%',
height: '300px'
}, this.getChartState());
}
componentDidUpdate() {
let el = ReactDom.findDOMNode(this);
d3Chart.update(el, this.getChartState());
}
getChartState() {
return {
data: this.props.data,
domain: this.props.domain
}
}
componentWillUnmount() {
let el = ReactDom.findDOMNode(this);
d3Chart.destroy(el);
}
render() {
return (
<div className="Chart">
</div>
);
}
}
我试图将d3.js
与componentWillUnmount
的反应进行整合;我正从DOM中删除图表元素。
除此之外,我在打开后使用componentWillUnmount
来清理引导模态。
我确信还有很多其他用例,但这些是我使用componentWillUnMount
的情况。我希望它可以帮助你。
答案 1 :(得分:5)
使用React创建Components
时,并非每个库都能很好地集成它想要管理DOM的理念。
这方面的一个例子是使用像c3这样的图形库。期望c3
被赋予一个DOM节点,并将从React创建/管理它自己的标记。在这种情况下,当从DOM中删除组件时,您应该管理清理由此库创建的任何元素。
import React, { Component, PropTypes } from 'react';
import c3 from 'c3';
export default class Graph extends Component {
componentDidMount () {
this._initGraph();
}
componentWillUnmount () {
this.graph = this.graph.destroy();
}
_initGraph () {
this.graph = c3.generate({
bindto: this.refs.graph
});
}
render () {
return (
<div className="graph">
<div className="graph__graph" ref="graph"></div>
</div>
);
}
}
此处React创建一个div
作为c3
的占位符来添加其内容。此过程在componentDidMount
生命周期挂钩中启动,并在componentWillUnmount
中再次清理。
答案 2 :(得分:3)
在这个简单的例子中(取自React Docs的例子)我用它来清除Clock组件的间隔。
例如,在您的页面中,您有2个标签,其中一个显示User Info
,第二个标签显示为User Schedule
,其中显示了那里的实时时钟。切换到User Schedule
标签后,将调用componentDidMount
来设置计时器。一旦切换回User Info
,就不需要保留此间隔挂钩,您可以在componentWillUnmount
事件中编写解除绑定/取消订阅逻辑。
import React from "react";
export default class Clock extends React.Component {
constructor(props) {
console.log("Clock", "constructor");
super(props);
this.state = {
date: new Date()
};
}
tick() {
this.setState({
date: new Date()
});
}
// These methods are called "lifecycle hooks".
componentDidMount() {
console.log("Clock", "componentDidMount");
this.timerID = setInterval(() => {
this.tick();
}, 1000);
}
// These methods are called "lifecycle hooks".
componentWillUnmount() {
console.log("Clock", "componentWillUnmount");
clearInterval(this.timerID);
}
render() {
return (
<div>It is {this.state.date.toLocaleTimeString()}.</div>
);
}
}
答案 3 :(得分:0)
简单的解决方案如下:
import React from "react"
export default class App extends React.Component {
isMounted = false
componentDidMount(){
this.isMounted = true
if (this.isMounted){
this.setState({'anyState': anyState}) //call setState if component isMounted
}
}
componentWillUnmount(){
this.isMounted = false
}
render(){
return(
<div />
)
}
}