React组件的生命周期详解

React中组件有生命周期,组件的生命周期,我们会分为四个阶段,初始化、运行中、销毁、错误处理;错误处理(16.3之后)

生命周期钩子函数一定不要写成箭头函数
在这里插入图片描述

初始化阶段

在组件初始化阶段会执行
1. constructor

  • React组件的构造函数在挂载之前被调用。在实现React.Component构造函数时,需要先在添加其他内容前,调用super(props),用来将父组件传来的props绑定到这个类中,使用this.props将会得到。

  • 官方建议不要在constructor引入任何具有副作用和订阅功能的代码,这些应当使用componentDidMount()。

  • constructor中应当做些初始化的动作,如:初始化state,将事件处理函数绑定到类实例上,但也不要使用setState()。如果没有必要初始化state或绑定方法,则不需要构造constructor,或者把这个组件换成纯函数写法。

  • 当然也可以利用props初始化state,在之后修改state不会对props造成任何修改,但仍然建议大家提升状态到父组件中,或使用redux统一进行状态管理。

2. static getDerivedStateFromProps(nextProps, prevState)

  • getDerivedStateFromProps 是react16.3 之后新增,在组件实例化后,和接受新的props后被调用。他必须返回一个对象来更新状态,或者返回null表示新的props不需要任何state的更新。
  • 如果是由于父组件的props更改,所带来的重新渲染,也会触发此方法。
  • 调用steState()不会触发getDerivedStateFromProps()。
  • 之前这里都是使用constructor+componentWillRecieveProps完成相同的功能的

3. componentWillMount() / UNSAFE_componentWillMount() 带有UNSAFE属于过时的钩子函数
> componentWillMount会在17版本之后弃用( 使用static getDerivedStateFromProps)
4. render()
render()方法是必需的。当他被调用时,他将计算this.props和this.state,并返回以下一种类型:

  • React元素。通过jsx创建,既可以是dom元素,也可以是用户自定义的组件。
  • 字符串或数字。他们将会以文本节点形式渲染到dom中。
  • Portals【'portl】。react 16版本中提出的新的解决方案,可以使组件脱离父组件层级直接挂载在DOM树的任何位置。
  • .null,什么也不渲染
  • 布尔值。也是什么都不渲染。
  • 当返回null,false,ReactDOM.findDOMNode(this)将会返回null,什么都不会渲染。
  • render()方法必须是一个纯函数,他不应该改变state,也不能直接和浏览器进行交互,应该将事件放在其他生命周期函数中。
    如果shouldComponentUpdate()返回false,render()不会被调用。

5.componentDidMount()

  • componentDidMount在组件被装配后立即调用。初始化使得DOM节点应该进行到这里。
  • 通常在这里进行ajax请求
  • 如果要初始化第三方的dom库,也在这里进行初始化。只有到这里才能获取到真实的dom.
import React ,{Component,Fragment} from 'react';

class LifeCircle extends Component{
   /*
   constructor钩子:作用:初始化属性或者定义状态
   初始化属性:用来将父组件传来的props绑定到这个类中,使用this.props将会得到
   */
   constructor( props ){
      super( props )
      this.state={
         msg:'你好'
      }
      console.log('1-constructor')
   }

   组件即将挂载
   componentWillMount(){
      /*将在React未来版本(官方说法 17.0)中被弃
      *组件即将挂载
      *做组件即将挂载的准备工作
      *数据可以获取到
      *真实dom没有拿到
      *可以进行数据请求和数据修改
      */
      console.log('2-componentWillMount')
      console.log(this.state.msg);
      console.log('h3',document.querySelector('h3'));
      console.log('p',document.querySelector('p'));

      fetch('./data.json')
      .then( res => res.json() )
      .then( data => {
         console.log(data)
         this.setState({
            msg:data.name
         })
      })
      .catch(err => console.log(err))
   }

   // static getDerivedStateFromProps( nextProps,prevState ){
   //     /*是react16.3之后新增
   //     *组件即将挂载
   //     *做组件即将挂载的准备工作
   //     *第一次渲染真实dom没有拿到
   //     *可以进行数据请求
   //    */
   //    console.log('getDerivedStateFromProps')
   //    console.log('nextProps',nextProps)
   //    console.log('prexState',prevState)
   //    console.log('h3',document.querySelector('h3'));
   //    console.log('p',document.querySelector('p'));

   //    fetch('./data.json')
   //    .then( res => res.json())
   //    .then( data => {
   //       console.log('data',data)
   //    })
   //    .catch(error => console.log(error))

   //    return {
   //       msg:'hello,明天'
   //    }
   // }

   render(){
      return (
         <Fragment>
            <h3>这里是生命周期测试</h3>
            <p> {this.state.msg} </p>
         </Fragment>
      )
   }

   componentDidMount () {
   /*
   组件挂载结束
   * 数据拿取到
   * 真实dom可以获取到
   * 可以数据请求 + 数据修改
   * 真实dom操作 【 第三方库的实例化 】

   */
      console.log('componentDidMount')
      console.log(this.state.msg);
      console.log('h3',document.querySelector('h3'));
      console.log('p',document.querySelector('p'));

      fetch('./data.json')
      .then(res => res.json())
      .then( data => {
         this.setState({
            msg:'修改的'
         })
      })

   }
}
export default LifeCircle;
更新阶段

涉及到触发的钩子函数:

  1. componentWillReceiveProps() / UNSAFE_componentWillReceiveProps()
  2. static getDerivedStateFromProps()
  3. shouldComponentUpdate() // react性能优化第二方案
  4. componentWillUpdate() / UNSAFE_componentWillUpdate()
  5. render()
  6. getSnapshotBeforeUpdate() ---- 将来会使用
  7. componentDidUpdate()
属性props变更触发钩子componentWillReceiveProps()
import React ,{Component,Fragment} from 'react';

class LifeCircle extends Component{

   render(){
      return (
         <Fragment>
            <h3>这里是生命周期测试</h3>
            <p> {this.props.name} </p>
         </Fragment>
      )
   }

   componentWillReceiveProps(nextProps){
      console.log('props改变触发')
      console.log(this.props.name)//属性原值
      console.log('nextProps',nextProps) //属性变更后的新值
   }
}
export default LifeCircle;

=============================================================================================
//在父组件内,子组件组件属性变化触发 componentWillReceiveProps()钩子
import React ,{Component} from 'react';

import './App.css';
import LifeCricle from './life_cricle/index'

class App extends Component {
   constructor(props) {
      super(props);
      this.state={
         flag:true,
      }
   }

   changeFlag = () => {
      this.setState({
         flag:!this.state.flag,
      })
   }
   
   render(){
      return (
         <div className="App">
            <button onClick = {this.changeFlag} >changeFlag</button>
           <LifeCricle name= { this.state.flag ?'o(=•ェ•=)m' :'U•ェ•*U '} ></LifeCricle>
         </div>
       );
   }
}

export default App;

componentWillReceiveProps ( nextProps ) 钩子:

  • 触发: props改变触发
  • 作用: 检测项目中的一些变化情况
    • React 路由监听
      nextProps.xxx === this.props.xxx ? 证明某一个属性( xxx )没有改变
      使用场景: 检测到项目中某一个按钮是否触发: 例如点击注册自动跳转登录
  • 官方建议使用getDerivedStateFromProps函数代替componentWillReceiveProps。当组件挂载后,接收到新的props后会被调用。
  • 如果需要更新state来响应props的更改,则可以进行this.props和nextProps的比较,并在此方法中使用this.setState()。
  • 如果父组件会让这个组件重新渲染,即使props没有改变,也会调用这个方法。
  • React不会在组件初始化props时调用这个方法。调用this.setState也不会触发。
整个更新阶段的钩子

import React ,{Component,Fragment} from 'react';

class LifeCircle extends Component{

   constructor( props ){
      super( props )
      this.state={
         msg:'你好'
      }
   }
   change = () => {
      this.setState({
         msg:'欢迎学习react'
      })
   }

   render(){
      return (
         <Fragment>
            <h3>这里是生命周期测试</h3>
            <p> {this.props.name} </p>
            <button onClick = { this.change} >change msg</button>
            <p> {this.state.msg} </p>
         </Fragment>
      )
   }

   // componentWillReceiveProps(nextProps){
   //    console.log('props改变触发')
   //    console.log('nextProps',nextProps)
   //    console.log(this.props.name)
   // }

   shouldComponentUpdate () {
      /* 
        作用: 决定组件是否要更新 
        必须要有返回值,默认返回值是true
      
      */
      console.log('shouldComponentUpdate')
      return true
    }
//     componentWillUpdate () {
//     /* 
//       组件即将更新
//       为整个更新,做准备工作
//       可以拿到更新前的数据 ,可以获得更新后的真实dom
//       在项目中: 
//           这个钩子项目中我们一般不去使用它
//        如果我们在这个钩子中使用  setState ,会发生死循环
//     */

//     // this.setState({//死循环
//     //   msg: '嗨起来'
//     // })

//     console.log('this.props.name ',this.props.name)
//     console.log('真实dom',document.querySelectorAll('p'))
//     console.log('componentWillUpdate')
//   }
  getSnapshotBeforeUpdate () {
   // 获得更新前的快照
   //这个生命周期返回的任何值都将作为参数传递给componentDidUpdate()。
   console.log('getSnapshotBeforeUpdate')
   return '组件更新了'
 }
 componentDidUpdate ( a,b,c ) {
   console.log( 'a',a) // 更新前的数据
   console.log( 'b',b) // 更新后的数据
   console.log( 'c',c) // getSnapshotBeforeUpdate 的返回值
   /* 
     * 组件更新结束
       * 可以拿取到更新之后的数据
       * 可以获得更新之后的真实DOM
       * 在更新发生后立即调用componentDidUpdate()。此方法不用于初始渲染。当组件更新时,将此作为一个机会来操作DOM。只要您将当前的props与以前的props进行比较(例如,如果props没有改变,则可能不需要网络请求),这也是做网络请求的好地方。
     * 项目:
       * 操作真实DOM【 第三方库的实例化 】
   */
   console.log('this.props.name ',this.props.name)
   console.log('真实dom',document.querySelectorAll('p'))
   console.log('componentDidUpdate')
 }
}


export default LifeCircle;
卸载阶段
外部开关卸载
import React ,{Component} from 'react';

import './App.css';
import LifeCricle from './life_cricle/index'

class App extends Component {
   constructor(props) {
      super(props);
      this.state={
         flag:false,
      }
   }

   removeFlag = () => {
      this.setState({
         flag:!this.state.flag,
      })
   }
   
   render(){
      return (
         <div className="App">
            <button onClick = {this.removeFlag} >removeFlag</button>
           { this.state.flag || <LifeCricle ></LifeCricle> }
         </div>
       );
   }
}

export default App;
组件内部卸载

import React,{ Component,Fragment } from 'react'
import ReactDOM from 'react-dom'

class LifeCircle extends Component{

  // eslint-disable-next-line no-useless-constructor
  constructor () {
    super()
      
  }

  componentWillMount () {
    this.timer = setInterval(() => {
      console.log('123')
    },1000)
  }

  destory = () => {
    /* 
      React组件内部销毁
        * unmountComponentAtNode( Node ) Node是整个项目最大的容器
          ReactDOM.unmountComponentAtNode( document.getElementById('root') ) 
        * 这个方法可以删除组件的DOM外壳
      不推荐使用

    */

    ReactDOM.unmountComponentAtNode( document.getElementById('root') )

  }

  render () {
    return (
      <Fragment>
        <h3> 生命周期 </h3>
        <button onClick = { this.destory }> 内部销毁 </button>
      
      </Fragment>
    )
  }

  componentWillUnmount () {
    /* 
      * 组件卸载时触发
        * 做善后
        * 计时器、滚轮事件‘第三方库实例化出来的实例
    */
   clearInterval( this.timer )
    console.log('componentWillUnmount')
  }
}


export default LifeCircle

错误处理阶段

  • componentDidCatch() — 16.3版本之后才有的
import React,{ Component,Fragment,logComponentStackToMyService } from 'react'

import Child from './Child'

class LifeCircle extends Component{

  constructor () {
    super()
    this.state = {
      flag: false
    }
  }

  static getDerivedStateFromError(error) {
    // 更新 state 使下一次渲染可以显示降级 UI
    console.log('getDerivedStateFromError')
    return { flag: true };
  }

  componentDidCatch(error, info) {
    // "组件堆栈" 例子:
    //   in ComponentThatThrows (created by App)
    //   in ErrorBoundary (created by App)
    //   in div (created by App)
    //   in App
    logComponentStackToMyService(info.componentStack);
  }


  render () {
    if( this.state.flag ){
      return <h1>Something went wrong.</h1>;
    }
    return (
      <Fragment>
        <h3> 生命周期 </h3>
        <hr/>
        <Child/>
      </Fragment>
    )
  }

}
export default LifeCircle
  • 错误边界是React组件,可以在其子组件树中的任何位置捕获JavaScript错误,记录这些错误并显示回退UI,而不是崩溃的组件树。错误边界在渲染期间,生命周期方法以及整个树下的构造函数中捕获错误。
  • 如果类组件定义了此生命周期方法,则它将成错误边界。在它中调用setState()可以让你在下面的树中捕获未处理的JavaScript错误,并显示一个后备UI。只能使用错误边界从意外异常中恢复; 不要试图将它们用于控制流程。
  • 错误边界只会捕获树中下面组件中的错误。错误边界本身不能捕获错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值