Home  >  Article  >  Web Front-end  >  Comprehensive understanding of react life cycle (with code)

Comprehensive understanding of react life cycle (with code)

不言
不言forward
2019-04-03 10:05:562717browse

This article brings you a comprehensive understanding of the react life cycle (with code). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

The life cycle of a React component is divided into three parts: instantiation, existence and destruction.

Instantiation phase

When the client renders, the following is called in sequence

  • getDefaultProps()
  • getInitialState()
  • componentWillMount()
  • render()
  • componentDidMount()

Server-side rendering

  • getDefaultProps()
  • getInitialState()
  • componentWillMount()
  • render()

Note: componentDidMount() will not be rendered on the server side;

getDefaultProps

For each component instance, this method will only be called once, and the component class In all subsequent applications, getDefaultPops will not be called again, and the object returned can be used to set default props values.

var Hello = React.creatClass({
    getDefaultProps: function(){
        return {
            name: 'pomy',
            git: 'dwqs'
        }
    },
    
    render: function(){
        return (
            <p>Hello,{this.props.name},git username is {this.props.dwqs}</p>
        )
    }
});

ReactDOM.render(<Hello />, document.body);

You can also set props when mounting the component.

var data = [{title: 'Hello'}];
<Hello data={data} />

Or call setProps (generally no need to call) to set its props

var data = [{title: 'Hello'}];
var Hello = React.render(<Demo />, document.body);
Hello.setProps({data:data});

But setProps can only be called on child components or component trees. Don't call this.setProps or modify this.props directly. Treat it as read-only data.

React provides a way to verify props through propTypes. propTypes is a configuration object used to define attribute types:

var survey = React.createClass({
    propTypes: {
        survey: React.PropTypes.shape({
            id: React.PropTypes.number.isRequired
        }).isRequired,
        onClick: React.PropTypes.func,
        name: React.PropTypes.string,
        score: React.PropTypes.array
        ...
    },
    
    //...
})

or

import React, { Component } from 'react'
import PropTypes from 'prop-types'

class BetterImage extends Component{...}

BetterImage.PropTypes={
  src: PropTypes.string,
  center: PropTypes.bool,
  loadingImage: PropTypes.string,
  defaultImage: PropTypes.string,
  onLoad: PropTypes.func,
  onError: PropTypes.func,
  onComplete: PropTypes.func
}
BetterImage.defaultProps={
  ....
}

getInitialState

For each instance of the component, this method is called once and only once to initialize the state of each instance. In this method, you can access the props of the component. Each React component has its own state, which differs from props in that state only exists inside the component, while props are shared among all instances.

There is a difference between the calls of getInitialState and getDefaultPops. getDefaultPops is only called once for the component class, and subsequent applications of this class will not be called, while getInitialState is called for each component instance. , and only adjust it once.

var LikeButton = React.createClass({
  //初始化State
  getInitialState: function() {
    return {liked: false};
  },
  
  handleClick: function(event) {
    //设置修改State
    this.setState({liked: !this.state.liked});
  },

  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);

Every time the state is modified, the component will be re-rendered. After instantiation, the component will be updated through the state, and the following methods will be called in sequence:

1、shouldComponentUpdate
2、componentWillUpdate
3、render
4、componentDidUpdate
  • componentWillMount

is called before rendering, both on the client and on the server. React officially released version v16.3. In this update, in addition to the new Context API that was hotly discussed some time ago, two newly introduced life cycle functions getDerivedStateFromProps and getSnapshotBeforeUpdate and three life cycle functions componentWillMount will be removed in the future v17.0 version. , componentWillReceiveProps, componentWillUpdate.

In this life cycle you will encounter the following problems:

a. No data on the first screen leads to a white screen
In React applications, many developers To avoid the white screen caused by not getting asynchronous data when the page is rendered for the first time, the code for the data request part is placed in componentWillMount, hoping to avoid the white screen and advance the sending time of the asynchronous request. But in fact, after componentWillMount is executed, the first rendering has already started, so if asynchronous data has not been obtained when componentWillMount is executed, the page will still be in a state without asynchronous data when it is first rendered. In other words, the component will always be in a state without asynchronous data when it is first rendered, so no matter where the data request is sent, there is no direct solution to this problem. Regarding sending data requests early, officials also encourage placing the data request part of the code in the constructor of the component instead of componentWillMount.
If there are two solutions that have been used to improve the user experience:

Method 1: Asynchronous request component, use nprogress to add loading animation;

import React, { Component } from 'react'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import './customNprogress.styl'

NProgress.configure({ showSpinner: false })

export default function asyncComponent(importComponent) {
  class AsyncComponent extends Component {
    state = {
      component: null
    }

    async componentDidMount() {
      NProgress.start()
      const { default: component } = await importComponent()
      NProgress.done()

      this.setState({ component })
    }

    render() {
      const C = this.state.component

      return C ? <C {...this.props} /> : null
    }
  }

  return AsyncComponent
}

const AsyncNotFound = asyncComponent(() => import(/* webpackChunkName: "NotFound" */ '@/routes/NotFound'))

Method 2: Use onreadystatechange to Listen to readyState and load a static page with only a frame before the resource loading is completed. The page does not request data. When the data request is completed, the route is switched to the real home page.

  function listen () {
    if (document.readyState == 'complete') { // 资源加载完成
        ReactDom.render(
            <Provider store={store}>
                <Router>
                    <Route path="/" component={Index}/>
                </Router>
            </Provider>,
            document.getElementById('root')
        )
    } else { // 资源加载中
        ReactDom.render(
            <Provider store={store}>
                <Router>
                    <Route path="/" component={FirstScreen}/>
                </Router>
            </Provider>,
            document.getElementById('root')
        )
    }
}

document.onreadystatechange = listen

Specific reference is to solve the problem of React first screen loading white screen

b.Event subscription

Another common use case is to subscribe to events in componentWillMount and in componentWillUnmount Cancel the corresponding event subscription. But in fact, React cannot guarantee that after componentWillMount is called, componentWillUnmount of the same component will also be called. An example of the current version is that when rendering on the server side, componentWillUnmount will not be called on the server side, so subscribing to events in componentWillMount will directly cause a memory leak on the server side. On the other hand, after React turns on asynchronous rendering mode in the future, after componentWillMount is called, the rendering of the component is likely to be interrupted by other transactions, resulting in componentWillUnmount not being called. **componentDidMount does not have this problem. After componentDidMount is called, componentWillUnmount will be called subsequently, and the event subscriptions existing in the component will be cleared according to the specific code. **

render

该方法会创建一个虚拟DOM,用来表示组件的输出。对于一个组件来讲,render方法是唯一一个必需的方法。render方法需要满足下面几点:

  • 只能通过 this.props 和 this.state 访问数据(不能修改)
  • 可以返回 null,false(这种场景下,react渲染一个
  • 只能出现一个顶级组件,不能返回一组元素
  • 不能改变组件的状态
  • 不能修改DOM的输出

render方法返回的结果并不是真正的DOM元素,而是一个虚拟的表现,类似于一个DOM tree的结构的对象。react之所以效率高,就是这个原因。

render执行情况如下:

1. 首次加载
2. setState改变组件内部state。
   注意: 此处是说通过setState方法改变。
3. 接受到新的props

注意:因为数据是异步的情况,会导致组件重复渲染

componentDidMount

该方法不会在服务端被渲染的过程中调用。该方法被调用时,已经渲染出真实的 DOM,可以再该方法中通过 this.getDOMNode() 访问到真实的 DOM(推荐使用 ReactDOM.findDOMNode())。

var data = [..];
var comp = React.createClass({
    render: function(){
        return <imput .. />
    },
    componentDidMount: function(){
        $(this.getDOMNode()).autoComplete({
            src: data
        })
    }
})

由于组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性:

var Area = React.createClass({
    render: function(){
        this.getDOMNode(); //render调用时,组件未挂载,这里将报错
        
        return <canvas ref=&#39;mainCanvas&#39;>
    },
    componentDidMount: function(){
        var canvas = this.refs.mainCanvas.getDOMNode();
        //这是有效的,可以访问到 Canvas 节点
    }
})

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。如果ref回调函数以inline函数的方式来指定,那么在组件更新的时候ref回调会被调用2次。第一次回调的时候传入的参数是null,而第二次的时候才真正的传入DOM节点

更多了解ref使用
从React官方文档看 refs 的使用和未来
获取真实dom,并获取dom css 三种方法

存在期

此时组件已经渲染好并且用户可以与它进行交互,比如鼠标点击,手指点按,或者其它的一些事件,导致应用状态的改变,你将会看到下面的方法依次被调用;

  1. componentWillReceiveProps()
  2. shouldComponentUpdate()
  3. componentWillUpdate()
  4. render()
  5. componentDidUpdate()

componentWillReceiveProps

当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用。

componentWillReceiveProps: function(nextProps){
    if(nextProps.checked !== undefined){
        this.setState({
            checked: nextProps.checked
        })
    }
}

了解更多点击此处

shouldComponentUpdate

shouldComponentUpdate函数是重渲染时render()函数调用前被调用的函数,它接受两个参数:nextProps和nextState,分别表示下一个props和下一个state的值。并且,当函数返回false时候,阻止接下来的render()函数及后面的 componentWillUpdate,componentDidUpdate 方法的调用,阻止组件重渲染,而返回true时,组件照常重渲染。

了解更多点击此处--真的讲的好

componentWillUpdate

这个方法和 componentWillMount 类似,在组件接收到了新的 props 或者 state 即将进行重新渲染前,componentWillUpdate(object nextProps, object nextState) 会被调用,注意不要在此方面里再去更新 props 或者 state。

componentDidUpdate

这个方法和 componentDidMount 类似,在组件重新被渲染之后,componentDidUpdate(object prevProps, object prevState) 会被调用。可以在这里访问并修改 DOM。

销毁

componentWillUnmount

每当React使用完一个组件,这个组件必须从 DOM 中卸载后被销毁,此时 componentWillUnmout 会被执行,完成所有的清理和销毁工作,在 componentDidMount 中添加的任务都需要再该方法中撤销,如创建的定时器或事件监听器。

当再次装载组件时,以下方法会被依次调用:

1、getInitialState
2、componentWillMount
3、render
4、componentDidMount

React v.16生命周期

constructor(props) // 初始化参数

componentWillMount()

render() // 第一次渲染 

componentDidMount()

**当父组件向子组件传入props发生改变后,依次调用**

componentWillReceiveProps(nextProps)

shouldComponentUpdate(nextProps, nextState) 

componentWillUpdate()

render() //子组件更新渲染

componentDidUpdate()

**当组件自身state发生变化后**

componentWillUpdate()

render() //组件再次更新渲染

componentDidUpdate()


当组件卸载

componentWillUnmount()

与低于React16版本的比较

  1. The new life cycle of React16 deprecated componentWillMount, componentWillReceiveProps, and componentWillUpdate
  2. Added getDerivedStateFromProps and getSnapshotBeforeUpdate to replace the three deprecated hook functions (componentWillMount, componentWillReceivePorps, componentWillUpdate)
  3. React16 has not deleted these three hook functions, but they cannot be mixed with the new hook functions (getDerivedStateFromProps, getSnapshotBeforeUpdate). React17 will delete componentWillMount, componentWillReceivePorps, componentWillUpdate
  4. Added new pairs Error handling (componentDidCatch)

[Related recommendations: react video tutorial]

The above is the detailed content of Comprehensive understanding of react life cycle (with code). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete