(16)React 进阶——⑥ React 生命周期函数(上):弄懂所有“生命周期函数” | React 基础理论实操

复制代码
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥"前端一万小时"两大明星专栏------"从零基础到轻松就业"、"前端面试刷题",已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

javascript 复制代码
涉及面试题:
 1. 组件生命周期的不同阶段是什么?
 2. React 生命周期方法有哪些?
 3. 在 React v16 中的错误边界是什么?
 4. 在 React v15 中如何处理错误边界?
 5. 在 componentWillMount() 方法中使用 setState() 好吗?
 6. 在 mounting 阶段生命周期方法的执行顺序是什么?
 7. 在 React v16 中,哪些生命周期方法将被弃用?
 8. 生命周期方法 getDerivedStateFromProps() 的目的是什么?
 9. 生命周期方法 getSnapshotBeforeUpdate() 的目的是什么?
10. 在组件类中方法的推荐顺序是什么?
11. 如何在调整浏览器大小时重新渲染视图?
12. 如何监听状态变化?
13. 如何每秒更新一个组件?
14. 为什么不能在 componentWillUnmount 中调用 setState() 方法?
15. 当组件重新渲染时顺序执行的方法有哪些?

编号:[react_16]

1 Initialization

"生命周期函数"是指:在某一时刻,"组件"会自动调用并执行的函数

"生命周期函数"是针对"组件 "而言的,每一个 "组件"都可以有以下"过程 "中所有的"生命周期函数":

接下来,我们结合 TodoList,按程序执行的"过程",分阶段把"生命周期函数"讲清楚。

❗️为了便于讲解,请将 TodoList 里的代码同步至《React 入门:⑥ TodoList 代码优化》中的版本。

1️⃣Initialization

  • 含义:初始化过程;

  • TodoList 中的代码实现:

javascript 复制代码
/*
🚀constructor 就是我们"初始化"的位置!我们会在这里去定义 state、去接收 props。

❓但,constructor 是不是一个"生命周期函数"呢?
答:
它符合"生命周期函数"的定义------在某一时刻,"组件"会自动调用并执行的函数。
所以,从某方面来说,我们可以把它理解为"生命周期函数"。
但是,constructor 不是 React 所独有的,它是 ES6 语法中自带的一个函数。
故,严格来说,我们不把它归类到 React 的"生命周期函数"里。
 */
constructor(props) {
  super(props);
  this.state = {
    inputValue: "", 
    list: []
  };
}

2 mounting

2️⃣mounting

  • 含义:组件"挂载"到页面上的过程;

  • TodoList 中的代码实现:

jsx 复制代码
import React, { Component, Fragment } from "react"; 

import TodoItem from "./TodoItem"; 

import "./style.css"; 

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: "", 
      list: []
    };
    
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleBtnClick = this.handleBtnClick.bind(this);
    this.handleItemDelete = this.handleItemDelete.bind(this);
    
  }

  componentWillMount() { /*
  											 2️⃣-①:这个"生命周期函数"是在"组件"
                         即将被"挂载"到页面的时刻自动执行;
                          
                         ❓什么是"挂载"?
                         答:"挂载"指"组件"第一次被放在页面的时候。
                          
                         ❗️故:一般来说,一个组件在页面上展示的时候,
                         componentWillMount 只会执行一次("挂载"的这个阶段)!
                          */
    
    console.log("componentWillMount") 
  }
  
  render() { // 2️⃣-②:这个"生命周期函数"是去做"组件"的"挂载";
    console.log("parent render")
    
    return(
      <Fragment>
        <div>
          <label htmlFor="insertArea">请输入要进行的事项:</label>    
        
          <input 
            id="insertArea"
      
            className="input"
            value={this.state.inputValue}
            onChange={this.handleInputChange}
          />

          <button onClick={this.handleBtnClick}>
            提交
          </button>
        </div>

        <ul>
          {this.getTodoItem()}
        </ul>

      </Fragment>
    )
  }
  
  componentDidMount() { /*
  											2️⃣-③:这个"生命周期函数"是在"组件"
  											被"挂载"到页面之后自动执行;
                         
                        ❗️一般来说,一个组件在页面上展示的时候,
                        componentDidMount 也只会执行一次("挂载"的这个阶段)!
                         
                        🏆请一定注意这个特点,下下篇文章,
                        我们会利用"只执行一次"这个特性,去进行 AJAX 数据的请求。
                         */
  
  	console.log("componentDidMount")  
  }

  getTodoItem() {
    return this.state.list.map((item, index) => { 
      return( 
        <TodoItem 
        	key={index}
        
        	content={item}
        	index={index} 
        	itemDelete={this.handleItemDelete}
        />  
      )  
    })
  }
  
  handleInputChange(e) {
    const value = e.target.value
    
    this.setState(() => ({
      inputValue: value
    }))
  }

  handleBtnClick() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],  
      inputValue: ""        
    }))
  }

  handleItemDelete(index) { 
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
        
      return {list}
 
    })
  }
}

export default TodoList;

看下页面的控制台(当组件成功"挂载"到页面后,再进行相关操作时, componentWillMountcomponentDidMount 都不再执行,但 render 会执行):

3 Updation

3️⃣Updation

  • 含义:组件"更新"的过程,即"数据"------state、props 发生变化的时候,页面的"更新"会被执行的过程;

  • TodoList 中的代码实现:

❗️我们先讲 props 和 states 发生变化时,它们所共有的"生命周期函数"的执行逻辑。

jsx 复制代码
import React, { Component, Fragment } from "react"; 

import TodoItem from "./TodoItem"; 

import "./style.css"; 

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: "", 
      list: []
    };
    
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleBtnClick = this.handleBtnClick.bind(this);
    this.handleItemDelete = this.handleItemDelete.bind(this);
    
  }

  componentWillMount() {
    
    console.log("componentWillMount") 
  }
  
  render() { 
    console.log("parent render")
    
    return(
      <Fragment>
        <div>
          <label htmlFor="insertArea">请输入要进行的事项:</label>    
        
          <input 
            id="insertArea"
      
            className="input"
            value={this.state.inputValue}
            onChange={this.handleInputChange}
          />

          <button onClick={this.handleBtnClick}>
            提交
          </button>
        </div>

        <ul>
          {this.getTodoItem()}
        </ul>

      </Fragment>
    )
  }
  
  componentDidMount() {  
  
    console.log("componentDidMount")  
  }

	shouldComponentUpdate() { /*
  													3️⃣-①:这个"生命周期函数"是在"组件"
  													被"更新"之前,会被自动执行;
                             */
    
  	console.log("shouldComponentUpdate")
  }

  getTodoItem() {
    return this.state.list.map((item, index) => { 
      return( 
        <TodoItem 
        	key={index}
        
        	content={item}
        	index={index} 
        	itemDelete={this.handleItemDelete}
        />  
      )  
    })
  }
  
  handleInputChange(e) {
    const value = e.target.value
    
    this.setState(() => ({
      inputValue: value
    }))
  }

  handleBtnClick() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],  
      inputValue: ""        
    }))
  }

  handleItemDelete(index) { 
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
        
      return {list}
 
    })
  }
}

export default TodoList;

在页面控制台查看一下打印出来的信息:

❌注意看页面的"警告": shouldComponentUpdate 函数需要返回一个"布尔值"。

为什么呢?从单词结构就可以看出,这是在"询问"我们:组件需要被"更新"吗?

  • true:更新,继续下一个"生命周期函数"的执行,页面产生相应的反馈;
  • false:不更新,后边的"生命周期函数"不再执行,页面不产生任何的反馈。

💡一般情况下,这里都是 true ,我们下篇文章会讲解 false 的用法(用于提高"组件"的性能)。

回到 TodoList.js 文件,继续讲解:

jsx 复制代码
import React, { Component, Fragment } from "react"; 

import TodoItem from "./TodoItem"; 

import "./style.css"; 

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: "", 
      list: []
    };
    
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleBtnClick = this.handleBtnClick.bind(this);
    this.handleItemDelete = this.handleItemDelete.bind(this);
    
  }

  componentWillMount() {
    
    console.log("componentWillMount") 
  }
  
  render() { /*
             3️⃣-③:"生命周期函数"render 会执行,根据变化了的"数据",
             重新"更新"页面;
              */
    console.log("parent render")
    
    return(
      <Fragment>
        <div>
          <label htmlFor="insertArea">请输入要进行的事项:</label>    
        
          <input 
            id="insertArea"
      
            className="input"
            value={this.state.inputValue}
            onChange={this.handleInputChange}
          />

          <button onClick={this.handleBtnClick}>
            提交
          </button>
        </div>

        <ul>
          {this.getTodoItem()}
        </ul>

      </Fragment>
    )
  }
  
  componentDidMount() {  
  
    console.log("componentDidMount")  
  }

  shouldComponentUpdate() { /*
  													3️⃣-①:这个"生命周期函数"是在"组件"
                            被"更新"之前,会被自动执行;
                             */
    
    console.log("shouldComponentUpdate")
    return true
    
  }

  componentWillUpdate() { /*
  												3️⃣-②:这个"生命周期函数"是在"组件"
                          被"更新"之前,shouldComponentUpdate 询问之后,
                          且得到 true 的"答复"后,才自动执行;
                           */
  
    console.log("componentWillUpdate")
  }

  componentDidUpdate() { /*
  											 3️⃣-④:这个"生命周期函数"是在"组件"
                         被"更新"完成之后,会自动执行。
                          */
    
    
    console.log("componentDidUpdate")
  }

  getTodoItem() {
    return this.state.list.map((item, index) => { 
      return( 
        <TodoItem 
        	key={index}
        
        	content={item}
        	index={index} 
        	itemDelete={this.handleItemDelete}
        />  
      )  
    })
  }
  
  handleInputChange(e) {
    const value = e.target.value
    
    this.setState(() => ({
      inputValue: value
    }))
  }

  handleBtnClick() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],  
      inputValue: ""        
    }))
  }

  handleItemDelete(index) { 
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
        
      return {list}
 
    })
  }
}

export default TodoList;

返回页面控制台查看打印信息:

接着,我们来看看 3️⃣中,props 和 states 不一样的部分------ componentWillReceiveProps

❓这个"生命周期函数"特殊在哪呢?

答:

TodoList 是一个"顶层组件",它并没有接收任何 props 。接收 props 最多的是 TodoItem 组件。即,这个"生命周期函数"只对拥有 props 参数的 TodoItem 组件生效。

打开 TodoItem.js 文件:

jsx 复制代码
import React, { Component } from "react";

class TodoItem extends Component {
  constructor(props) {
    super(props);
    
    this.handleClick = this.handleClick.bind(this);
  } 
  
  render() {
    const {content} = this.props
    
    return(
      <div onClick={this.handleClick}> 
        {content}  
      </div>
    )
  }
  
  handleClick() {  
    const {itemDelete, index} = this.props
    
    itemDelete(index)
  }

  componentWillReceiveProps() { /*
  															❗️❗️❗️这个"生命周期函数"要执行,需同时满足以下条件:
                                ①:这个组件要从父组件接收"参数";
                                ②:如果这个组件"第一次"存在于父组件中,这个"生命周期函数"不会执行;
                                ③:如果这个组件之前已经存在于父组件中,这个"生命周期函数"才会执行。
                                 */
  
    console.log("child componentWillReciveProps")
  }
}

export default TodoItem;

返回页面控制台查看打印信息:

4 Unmounting

4️⃣Unmounting

  • 含义:把"组件"从页面上去除的过程;

  • TodoList 中的代码实现(打开 TodoItem.js 文件):

jsx 复制代码
import React, { Component } from "react";

class TodoItem extends Component {
  constructor(props) {
    super(props);
    
    this.handleClick = this.handleClick.bind(this);
  } 
  
  render() {
    const {content} = this.props
    
    return(
      <div onClick={this.handleClick}> 
        {content}  
      </div>
    )
  }
  
  handleClick() {  
    const {itemDelete, index} = this.props
    
    itemDelete(index)
  }

  componentWillReceiveProps() { 
    console.log("child componentWillReciveProps")
  }

	componentWillUnmount() { /*
  												 ❗️❗️❗️这个"生命周期函数"是在"组件"
  												 即将被程序从页面上剔除时,会自动执行。
                            */
  
  	console.log("child componentWillUnmount")
  }

}

export default TodoItem;

返回页面控制台查看打印信息:

祝好,qdywxs ♥ you!

相关推荐
拉不动的猪1 分钟前
前端常见数组分析
前端·javascript·面试
小吕学编程18 分钟前
ES练习册
java·前端·elasticsearch
Asthenia041225 分钟前
Netty编解码器详解与实战
前端
袁煦丞30 分钟前
每天省2小时!这个网盘神器让我告别云存储混乱(附内网穿透神操作)
前端·程序员·远程工作
一个专注写代码的程序媛1 小时前
vue组件间通信
前端·javascript·vue.js
一笑code2 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员2 小时前
layui时间范围
前端·javascript·layui
NoneCoder2 小时前
HTML响应式网页设计与跨平台适配
前端·html
凯哥19702 小时前
在 Uni-app 做的后台中使用 Howler.js 实现强大的音频播放功能
前端
烛阴2 小时前
面试必考!一招教你区分JavaScript静态函数和普通函数,快收藏!
前端·javascript