如何在ReactJs中正确使用componentWillUnmount()

时间:2016-11-23 09:19:27

标签: javascript reactjs

从官方教程:

  在卸载和销毁组件之前立即调用

componentWillUnmount()。在此方法中执行任何必要的清理,例如使计时器无效,取消网络请求或清除在componentDidMount

中创建的任何DOM元素

我理解“使计时器无效”。可以使用fetch中止AbortController。但我不明白“清理componentDidMount中创建的任何DOM元素”,我能看到这种情况的例子吗?

4 个答案:

答案 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.jscomponentWillUnmount的反应进行整合;我正从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 />
    )
  }
}