react笔记_05生命周期(类组件)


组件从创建到销毁会经历一系列的特定的阶段,React组件中会包含一系列的生命周期钩子,会在特定时刻调用。
在此将以类组件为例,讲述一下组件的挂载、更新、卸载的过程。

生命周期(旧)

生命周期

在这里插入图片描述

componentWillMount
componetdidMount
shouldComponentUpdate

在react开发中, 大部分数据需要使用state存储,更改时使用setState去修改。
默认情况下,在通过setState去修改数据时会重新渲染整个组件树,若是在某次setState更改数据时不想要重新渲染,可以在shouldComponentUpdate 生命周期钩子中做判断。
在该生命周期函数中,若是返回值为true表示重新渲染,若是返回值为false表示不重新渲染(即使数据改变了)
默认

shouldComponentUpdate(nextProps, nextState){
 return true 
}

若是在组件中没有显示声明该生命周期,默认情况下会重新渲染整个dom树。
声明
声明该函数时,当通过setState去修改数据时,react会调用此函数并传入两个参数

  • nextProps : 表示下一个props
  • nextState: 表示下一个state的值

可以对比当前props与下一次的props、当前state与下一次的state来决定是否需要重新渲染组件;
若是当前state中传入的值和通过props接收的值在修改时都需要重新渲染,那么就不需要声明该函数。

componentWillUpdate
componentDidUpdate

该组件有两个参数 preState preprops

componentWillUnmount
componentWillReceiveProps

组件即将接受props

组件的挂载、更新、销毁
案例1

在这里插入图片描述

  • 如上图 数量num存储在state中;
  • 当点击按钮 “点我加1” 时会通过 setState 去修改state中的num值;
  • 当点击 “点我强制更新” 时会通过 forceUpdate 去强制更新页面;
  • 当点击 “点我销毁组件” 时会 取消该组件的挂载;
<div id="test"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- 案例:数值 按钮(每次点击按钮数字加1) -->
<script type="text/babel">
  class Mycomponent extends React.Component{
    constructor(props){
      console.log('---constructor---')
      super(props)
      this.state={num:0}
    }
    render(){
      console.log('---render---')
      return (
        <div >
          <span ref='span'>{this.state.num}</span>
          <button onClick={this.addNum}>点我加1</button>
          <button onClick={this.force}>点我强制更新</button>
          <button onClick={this.unmount}>点我销毁组件</button>
        </div>
      )
    }
    componentWillMount(){
      console.log('---componentWillMount---', this.state, this.refs) //{num:0},{}
    }
    componentDidMount(){
      console.log('---componentDidMount---', this.state, this.refs) // {num:0},{span:span(dom)}
    }
    shouldComponentUpdate(){
      console.log('---shouldComponentUpdate---')
      // return false // 及时通过setState更新状态视图也不会重新渲染
      return true // 默认返回值
    }
    componentWillUpdate(){
      console.log('---componentWillUpdate---')
    }
    componentDidUpdate(){
      console.log('---componentDidUpdate---')
    }
    addNum = ()=>{
      const {num} = this.state
      this.setState({num:num+1})
    }
    force = ()=>{
      this.forceUpdate()
      // 不会判断需不需要更新-直接更新
    }
    unmount = ()=>{
      ReactDOM.unmountComponentAtNode( document.getElementById('test')) // 销毁组件而不能销毁节点
    }
    componentWillUnmount(){
      console.log('---componentWillUnMount----')
    }
  }
  ReactDOM.render(<Mycomponent /> , document.getElementById('test'))
</script>
渲染过程

结合生命周期图以及案例1理解一下渲染过程:

  • [1]
    ReactDOM.render(<Mycomponent /> , document.getElementById('test'))
    
    发现标签名首字母大写 -> 去寻找对应的组件
  • [2] 发现组件是一个类组件 -> 通过new关键字实例化对象
    • 在实例化对象过程中,会自动调用 构造器(constructor) -> 创建实例对象并修改this指向;
  • 获取到实例化对象后
    • [3] 通过实例化对象调用componentWillMount函数 -> 在此已经初始化数据但是还没有挂载dom
    • [4] 通过实例化对象调用render函数 -> 在此获取虚拟dom
    • [5] 通过实例化对象调用componetdidMount函数 -> 在此vdom已经挂载到dom元素上

因此在案例1中,一进入页面就会在控制台打印如下
在这里插入图片描述

更新过程1-通过setState去修改数据

结合生命周期图以及案例1理解一下更新过程:

  • [1] 当点击“点我加1”按钮时,会通过setState去修改state中的数据
  • [2] 当通过setState去修改数据时,react会通过实例化对象调用shouldComponentUpdate-> 判断组件是否应该被更新
    • 返回值为true -> 组件确认被更新
      • [3] 调用 componentWillUpdate ->组件即将被更新
      • [4] 调用 render -> 获取更新后的vdom
      • [5] 调用 componentDidUpdate -组件已经被更新
    • 返回值为false -> 组件确认不更新 ->结束

因此在案例1中,点击“点我加1”按钮时就会在控制台打印如下
在这里插入图片描述
若是将shouldComponentUpdate钩子的返回值改为false, 则点击“点我加1”按钮时就会在控制台打印如下
在这里插入图片描述
–> 返回值为false更新停止;

更新过程2-通过forceUpdate强制更新

结合生命周期图以及案例1理解一下更新过程:

  • 当点击“点我强制更新”按钮时,会去重新渲染整个组件树(不会去判断是否需要更新)
  • 更新过程
    • [1]调用 componentWillUpdate ->组件即将被更新
    • [2] 调用 render -> 获取更新后的vdom
    • [3] 调用 componentDidUpdate -组件已经被更新

因此在案例1中,点击“点我强制更新”按钮时就会在控制台打印如下
在这里插入图片描述

销毁过程

结合生命周期图以及案例1理解一下销毁过程:

  • 当点击“点我销毁组件”按钮时,会去卸载dom
  • 销毁过程
    + 调用 componentWillUnmount ->组件即将被销毁

因此在案例1中,点击“点我销毁组件”按钮时就会在控制台打印如下
在这里插入图片描述

父子组件的挂载、更新、销毁
案例2

在这里插入图片描述

  • 如上图 在父组件的state中定义了两个数据-value、num
    • value在自身组件中使用
    • num传递给了子组件在子组件中使用
  • 当点击 “点我修改num” 按钮时会通过setState去修改 父组件的num值;
  • 当点击“点我修改value” 按钮时会通过setstate去修改父组件的value值;
  • 当点击 “点我强制刷新” 按钮时会重新渲染父组件的组件树;
<div id="test"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel"> 
  class Fa extends React.Component{
    constructor(props){
      super(props)
      this.state ={ value:111, num:0 }
      console.log('父组件-constructor')
    }
    render(){
      console.log('父组件-render')
      return (
        <div>
          <h1>我是父组件</h1>
          {this.state.value}
          <button onClick={this.editnum}> 点我修改num</button>
          <button onClick={this.editvalue}> 点我修改value</button>
          <button onClick={this.force}> 点我强制刷新</button>
          <Son num={this.state.num}/>  
        </div>
      )
    }
    componentWillMount(){
      console.log('父组件-componentWillMount')
    }
    componentDidMount(){
      console.log('父组件-componentDidMount')
    }
    shouldComponentUpdate(){
      console.log('父组件-shouldComponentUpdate')
      return true
    }
    componentWillUpdate(){
      console.log('父组件-componentWillUpdate')
    }
    componentDidUpdate(){
      console.log('父组件-componentDidUpdate')
    }
    componentWillUnmount(){
      console.log('父组件-componentWillUnmount')
    }

    editnum = ()=>{
      const {num} = this.state
      this.setState({num:num+1})
    }
    editvalue = ()=>{
      const {value} = this.state
      this.setState({value:value+1})
    }
    force = ()=>{
      this.forceUpdate()
      // 不会判断需不需要更新-直接更新
    }

  }
  class Son extends React.Component{
    constructor(props){
      super(props)
      console.log('子组件-constructor')
    }
    render(){
      const {num} = this.props
      console.log('子组件-render')
      return(
        <div>
          <h1>我是子组件</h1>
          <span>{num}</span>
        </div>
      )
    }
    componentWillReceiveProps(props){
      console.log('接收props', props)
    }
    componentWillMount(){
      console.log('子组件-componentWillMount')
    }
    componentDidMount(){
      console.log('子组件-componentDidMount')
    }
    shouldComponentUpdate(){
      console.log('子组件-shouldComponentUpdate')
      return true
    }
    componentWillUpdate(){
      console.log('子组件-componentWillUpdate')
    }
    componentDidUpdate(){
      console.log('子组件-componentDidUpdate')
    }
    componentWillUnmount(){
      console.log('父组件-componentWillUnmount')
    }

  }
  ReactDOM.render(<Fa /> , document.getElementById('test'))
</script>
渲染过程

案例2一进入页面,在控制台打印结果如下:
在这里插入图片描述
挂载组件是一个由内向外的过程.

  • [1]
    ReactDOM.render(<Fa /> , document.getElementById('test'))
    
    (父)发现标签名首字母大写 -> 去寻找对应的组件
  • [2] (父)发现组件是一个类组件 -> 通过new关键字实例化对象。在创建实例化对象过程中,会自动调用 构造器(constructor) -> 创建实例对象并修改this指向;
  • 获取到实例化对象后
    • [3] (父)通过实例化对象调用componentWillMount函数 -> 在此已经初始化数据但是还没有挂载dom
    • [4] (父)通过实例化对象调用render函数 -> 在此获取虚拟dom
    • [5] (父-子)此时发现虚拟dom中存在组件 -> 去寻找对应的组件
    • [6] (子)发现子组件是一个类组件 -> 通过new关键字实例化对象
      • (子)在实例化对象过程中,会自动调用 构造器(constructor) -> 创建实例对象并修改this指向;
    • 获取到实例化对象后
      • [7] (子)通过实例化对象调用componentWillMount函数 -> 在此已经初始化数据但是还没有挂载dom
      • [8] (子)通过实例化对象调用render函数 -> 在此获取虚拟dom
      • [9] (子)挂载dom是一个由内向外的过程,通过实例化对象调用componetdidMount函数 -> 在此vdom已经挂载到dom元素上
    • [10] (父)通过实例化对象调用componetdidMount函数 -> 在此vdom已经挂载到dom元素上
更新过程1-通过setState去修改数据(num)

更新组件是一个由内向外的过程.

案例2当点击“点我修改num”按钮时,在控制台打印结果如下:
在这里插入图片描述

  • (父)判断是否需要更新
    • 不需要更新-> 结束(子组件也不会更新了)
    • 需要更新 -> 进行更新
      • (父)shouldComponentUpdate
      • (父)render -> 获取更新后的vdom -> 发现存在子组件
      • (子)componentWillReceiveProps -> 组件即将接收props
      • (子)判断是否需要更新
        • (子)不需要更新-> 子组件更新结束
        • (子)需要更新 -> 进行更新
          • (子)shouldComponentUpdate
          • (子)render -> 获取更新后的vdom
          • (子)componentDidUpdate
      • (父)componentDidUpdate
更新过程1-通过setState去修改数据(value)

案例2当点击“点我修改value”按钮时,在控制台打印结果如下:
在这里插入图片描述
发现value和子组件没有任何关系,当value改变时子组件依旧会重新渲染,也就是说只要是组件通过setState去修改数据,默认情况下会重新渲染整个组件树(包含子组件)!!!!!
若是不想重新渲染子组件,可以这样写

shouldComponentUpdate(nextprops){
  console.log('子组件-shouldComponentUpdate', nextprops)
  return nextprops.num != this.props.num
    }

这样就是仅仅在num值改变时才会重新渲染子组件了。

  • 若是修改num, 控制台打印结果如下:
    • 在这里插入图片描述
  • 若是修改value,控制台打印结果如下:
    • 在这里插入图片描述
更新过程3-通过forceUpdate强制更新

案例2当点击“点我强制刷新”按钮时,在控制台打印结果如下:
在这里插入图片描述

  • 当通过forceUpdate强制刷新时
    • 父组件是强制刷新
    • 子组件还是会走shouldComponentUpdate钩子去判断是否刷新.
销毁过程

销毁组件也是一个由内向外的过程.

生命周期(新)

生命周期图

在这里插入图片描述
在17版本+
不推荐使用:componentWillMount componentWillUpdate componentWillReceiveProps 不推荐使用,使用时会报一个警告
新添加两个生命周期钩子(使用较少):
getDerivedStateFromProps
该函数的参数为props state
该函数的返回值将直接作为state值进行渲染->应用在state的值在任何时候都依赖于props
getSnapshotBeforeUpdate
该函数的参数 preprops prestate 传递组件更改前的一些信息
该函数的返回值将作为 conponentDidUpdate生命周期的第三个参数

函数组件

函数组件没有继承React.Component组件,因此函数组件是不存在生命周期的,但是我们可以看一下函数组件的渲染、更新、销毁过程

  • 挂载组件 :react会直接调用该函数,并自动传入props参数;
  • 更新组件:react会重新调用此函数

而在类组件中更新组件并不会重新通过new关键字实例化对象,而是重新执行自己的render方法 -> 也就是说实例一直都是同一个

tips: 虽然实力化对象是同一个,但是在实力化对象中this数据是实时更新的!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值