0207生命周期v17.x-组件-React

news/2024/7/15 18:52:50 标签: react.js, javascript, 前端

1 新版生命周期

React17.x生命周期如下图1-1所示:

在这里插入图片描述

React组件的生命周期可以分为三个主要阶段:挂载阶段,更新阶段和卸载阶段。每个阶段都有不同的生命周期方法可供使用。

  1. 挂载阶段(Mounting)

在挂载阶段,组件将被插入到DOM中。以下是挂载阶段的生命周期方法:

  • constructor():组件被创建时调用,初始化组件的状态和绑定方法。
  • static getDerivedStateFromProps():在组件挂载之前和更新时调用,可以根据新的props计算state。
  • render():在组件挂载之前和更新时调用,返回虚拟DOM,用于渲染到页面。
  • componentDidMount():在组件挂载后调用,可以执行DOM操作或发起网络请求等操作。
  1. 更新阶段(Updating)

在更新阶段,组件的props或state被修改,导致重新渲染。以下是更新阶段的生命周期方法:

  • static getDerivedStateFromProps():在组件更新时调用,可以根据新的props计算state。
  • shouldComponentUpdate():在组件更新时调用,决定是否需要重新渲染组件,可以优化性能。
  • render():在组件更新时调用,返回虚拟DOM,用于渲染到页面。
  • getSnapshotBeforeUpdate():在组件更新之前调用,可以获取更新前的DOM状态。
  • componentDidUpdate():在组件更新后调用,可以执行DOM操作或发起网络请求等操作。
  1. 卸载阶段(Unmounting)

在卸载阶段,组件将从DOM中移除。以下是卸载阶段的生命周期方法:

  • componentWillUnmount():在组件卸载前调用,可以执行清理操作,如取消网络请求或定时器等。

还有一些其他的生命周期方法,如错误处理的 componentDidCatch() 和 getDerivedStateFromError() 方法。这些方法可以帮助开发者更好地管理组件的生命周期和错误处理。

2 与旧版对比

React 17.x版本没有引入新的生命周期方法,但是对生命周期方法的行为进行了一些改变。

  1. 生命周期方法的弃用

React 17.x废弃了三个生命周期方法:componentWillMount()、componentWillReceiveProps()、componentWillUpdate()。这些方法在React 16.x版本中仍然可用,但在React 17.x版本中不推荐使用。取而代之的是,React 17.x推荐使用新的静态方法getDerivedStateFromProps()和getDerivedStateFromError()来代替。

  1. 组件更新

在React 16.x版本中,React会在shouldComponentUpdate()方法返回true后,调用render()方法和componentDidUpdate()方法。但是在React 17.x版本中,如果shouldComponentUpdate()方法返回false,React仍然会调用render()方法,但是不会调用componentDidUpdate()方法。这个改变使得React在一些情况下更加灵活,同时也提高了性能。

  1. 事件处理器的绑定

在React 17.x版本中,React要求所有事件处理器的绑定必须在构造函数中完成。这个改变可以使得React在更新时更加高效,并且减少了一些错误的发生。

综上所述,React 17.x版本在生命周期方法的行为上与React 16.x版本相比并没有太大的变化,但是在一些细节上进行了改进,以提高性能和可靠性。同时,React 17.x版本也为未来的版本打下了基础,使得React可以更好地适应新的技术和应用场景。

测试代码同之前一致,限制只是把js换成React17.0.1,旧版生命周期函数在17.x中仍然可以使用,但是由警告,如下所示:

react-dom.development.js:61 Warning: componentWillMount has been renamed, and is not recommended for use. See https://reactjs.org/link/unsafe-component-lifecycles for details.

* Move code with side effects to componentDidMount, and set initial state in the constructor.
* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.

点击链接,跳转到官网。大意是在之后发布的版本中,这3个函数会加上UNSAFE_前缀。不是代表它们不安全,而是在未来的版本中使用可能由bug,特别是在异步渲染中。

3 getDerivedStateFromProps

getDerivedStateFromProps是React生命周期方法之一,用于根据props计算和更新state。该方法在组件挂载和更新时都会被调用。

getDerivedStateFromProps(props, state)方法接收两个参数,props表示组件的props,state表示组件的state。该方法必须返回一个对象,用于更新组件的state。

在React 16.x版本中,getDerivedStateFromProps通常被用于解决props和state不同步的问题,特别是当组件的props和state都受到外部因素的影响时。例如,当组件从父组件中接收props并更新自己的state时,可以使用getDerivedStateFromProps方法来保持props和state的同步。

在React 17.x版本中,getDerivedStateFromProps方法不再推荐用于处理props和state同步的问题。取而代之的是,React推荐使用useEffect() hook或者componentDidUpdate()方法来处理这个问题。

需要注意的是,getDerivedStateFromProps方法是一个静态方法,不能访问this关键字,也不能调用组件的实例方法。如果需要访问组件的实例方法或属性,可以将它们作为props传递给组件。

测试如下代码3-1所示:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>1205_updating-生命周期(新)</title>
</head>

<body>
  <div id="test"></div>
  <!-- react核心库 -->
  <script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
  <!-- 用于支持react操作DOM -->
  <script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
  <!-- 用于将jsx转为js -->
  <script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

  <script type="text/babel">

    /**
     * 创建组件
     *  生命周期函数:生命周期钩子函数
     */
    class Count extends React.Component {
      constructor(props) {
        console.log('Count === constructor');
        super(props)
        // 初始化状态
        this.state = {
          count: 1 // 计数
        }
      }


      /**
       * +1
       */
      add = () => {
        this.setState({count: this.state.count + 1})
      }

      /**
       * 不更新状态,强制更新
       */
      force = () => {
        console.log('Count ==== forceUpate');
        this.forceUpdate()
      }



      /**
       * 卸载组件
       */
       remove = () => {
        ReactDOM.unmountComponentAtNode(document.getElementById('test'))
      }

      /**
      * 获取从props派生的state
      */ 
      static getDerivedStateFromProps(props, state) {
        console.log('Count ==== getDerivedStateFromProps');
        console.log(props, '----', state);
        return null
        // return props
      }

      /**
       * 组件挂载完毕
       */
      componentDidMount() {
        console.log('Count === componentDidMount');
      }
      
      /**
       * 组件是否应该被更新
       */
      shouldComponentUpdate(nextProps, nextState) {
        console.log('count === shouldComponentUpdate :', nextProps, '----', nextState);
        return true;
      }

      /**
       * 组件将要被更新之后
       */
       componentDidUpdate(prevProps, prevState) {
        console.log('count === componentDidUpdate :', prevProps, '----', prevState);
      }

      /**
       * 组件卸载之前
       */
      componentWillUnmount() {
        console.log('Count === componentWillUnmount');
      }

      /**
       * 初始化渲染,状态更新重新渲染
       */
      render() {
        console.log('Count === render');
        const { count } = this.state
        return (
          <div>
            <h2>当前计数:{count}</h2><br />
            <button onClick={this.add}>点我+1</button><br/>
            <button onClick={this.force}>不更改状态强制更新</button>
            </div>
        )
      }
    }

    // 2.渲染虚拟DOM到页面
    ReactDOM.render(<Count count={99}/>, document.getElementById('test'))

  </script>
</body>

</html>

getDerivedStateFromProps 此方法 适用于及其罕见的案例,即state的值在任何时候都取决于props,目前在开发中很少使用。

4 getSnapshotBeforeUpdate

getSnapshotBeforeUpdate是React生命周期方法之一,在组件更新之前被调用,用于获取组件更新前的一些信息。该方法的返回值会作为第三个参数传递给componentDidUpdate()方法。

getSnapshotBeforeUpdate(prevProps, prevState)方法接收两个参数,prevProps表示组件更新前的props,prevState表示组件更新前的state。该方法必须返回一个值,用于在componentDidUpdate()方法中进行处理。

在React 16.x版本中,getSnapshotBeforeUpdate通常被用于获取组件更新前的某些信息,例如组件的滚动位置。获取到的信息可以在componentDidUpdate()方法中进行处理,例如恢复滚动位置等。

在React 17.x版本中,getSnapshotBeforeUpdate方法的行为与React 16.x版本相同,但是该方法不再推荐使用。取而代之的是,React推荐使用useEffect() hook或者componentDidUpdate()方法来处理获取组件更新前的信息。

需要注意的是,getSnapshotBeforeUpdate方法在组件挂载时不会被调用,只有在组件更新时才会被调用。同时,如果shouldComponentUpdate()方法返回false,getSnapshotBeforeUpdate()方法也不会被调用。

测试代码同上,加上getSnapshotBeforeUpdate方法,新增代码4-1如下所示:

/**
 * 获取更新前的快照
 */ 
 getSnapshotBeforeUpdate(prevProps, prevState) {
  console.log('Count ==== getSnapshotBeforeUpdate');
  console.log(prevProps, '----', prevState);
  return '你好呀';
}

/**
 * 组件更新之后
 */
 componentDidUpdate(prevProps, prevState, snapshot) {
  console.log('count === componentDidUpdate :', prevProps, '----', prevState);
  console.log('snapshot: ', snapshot);
}

效果如下图4-1所示

在这里插入图片描述

下面通过一个小案例,演示下该生命周期函数的应用场景。场景描述,又一个新闻列表,持续产生新的新闻,新闻出现在最上边。新闻盒子有固定高度,当新闻盒子满时,超出的旧新闻隐藏。我们希望实现当我们滚动到第几条新闻时,展示区域固定展示我们到的新闻,新新闻持续产生。

效果图示如下4-2所示:

在这里插入图片描述

实现代码如下4-2所示:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>1206_getSnapshotBeforeUpdate应用场景-生命周期()</title>
  <style>
    .list{
      width: 200px;
      height: 150px;
      background-color: skyblue;
      overflow: auto;
    }
    .news{
      height: 30px;
    }
  </style>
</head>

<body>
  <div id="news"></div>
  <!-- react核心库 -->
  <script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
  <!-- 用于支持react操作DOM -->
  <script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
  <!-- 用于将jsx转为js -->
  <script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

  <script type="text/babel">

    /**
     * 创建组件
     *  生命周期函数:生命周期钩子函数
     */
    class NewsList extends React.Component {

      state = {newsArr: []}
      

      componentDidMount() {
        setInterval(() => {
          // 获取原状态
          const {newsArr} = this.state
          const news = '新闻' + (newsArr.length + 1)
          // 更新状态
          this.setState({newsArr: [news, ...newsArr]})
        }, 1000);
      }


      getSnapshotBeforeUpdate() {
        // 获取内容高度
        return this.refs.list.scrollHeight
      }

    componentDidUpdate(prevProps, prevState, prevHeight) {
      // 滚动条持续滚动
       this.refs.list.scrollTop += this.refs.list.scrollHeight - prevHeight
    }

      /**
       * 初始化渲染,状态更新重新渲染
       */
      render() {
        return (
          <div className="list" ref='list'>
            {
              this.state.newsArr.map((n, index) => {
                return <div className="news" key={index}>{n}</div>
              })
            }
          </div>
        )
      }
    }

    // 2.渲染虚拟DOM到页面
    ReactDOM.render(<NewsList/>, document.getElementById('news'))

  </script>
</body>

</html>

后记

❓QQ:806797785

⭐️源代码仓库地址:https://gitee.com/gaogzhen/react-study

参考:

[1]React视频教程[CP/OL].2020-12-15.p43-p47.

[2]React官网[CP/OL].

[2]ChatGPT[CP/OL].


http://www.niftyadmin.cn/n/179130.html

相关文章

复习Java基础知识-数据类型

基本数据类型 整数型 btye 1字节 short 2字节 int 4字节 long 8字节 浮点型 float 4字节 double 8字节 布尔型 boolean 字符型 char 引用类型 字符串String 字符串的不可变性 String a "abc"; a "bcd"; a赋值改变的这个过程不是将字符串“abc”的内…

C++ 直接初始化和拷贝初始化

首先我们介绍直接初始化&#xff1a;编译器使用普通的函数匹配来选择与我们提供的参数最匹配的构造函数。文字描述可能会让你们云里雾里&#xff0c;那我们直接看代码&#xff1a; //先设计这样的一个类 class A{ public:A(){ cout << "A()" << endl; }A…

Js:Blob、ArrayBuffer、FileReader、URL、Image、关于文件下载的方法案例

目录概括1. 基本概念1.1 Blob&#xff1a;存储二进制文件的“容器”。不可变。1.2 File&#xff1a;File接口基于Blob1.3 ArrayBuffer &#xff1a;表示原始的二进制数据缓冲区1.4 FileReader&#xff1a;异步文件读取&#xff0c;可进行文件类型转换1.5 URL.createObjectURL()…

MySQL实战45讲——06|全局锁和表锁:给表加个字段怎么有这么多阻碍

06|全局锁和表锁&#xff1a;给表加个字段怎么有这么多阻碍 请支持正版&#xff1a;MySQL实战45讲 根据锁的范围&#xff0c;MySQL里的锁大致可以分为全局锁、表级锁和行锁三类 全局锁 全局锁就是对整个数据库实例加锁&#xff0c;MySQL提供了一个加全局读锁的方法&#xf…

测试了Copilot辅助编程后,就离不开这个AI工具了

微软用chatGPT 4 对github copilot X 升级后&#xff0c;也跟风测试了一下其功能。copilot 与vscode结合&#xff0c;智能化程度之高&#xff0c;令我吃惊。 下面简单介绍一下其使用过程&#xff0c;以及对如何使用好这个工具. 1. 安装与注册 IDE开发环境我使用的是 VSCode与…

深入学习hashCode 和equals()方法的关系

在java中&#xff0c;每个对象都可以调用hashCode()方法得到自己的哈希值(一串数值)&#xff0c;就像人的指纹一样。但是在java中对象并不能做到像人一样&#xff0c;指纹都是唯一的。 在判断两个对象之间是否想等时&#xff0c;我们通常使用hashCode()方法和equals()方法。 …

Linux运行基本容器

安装容器管理工具在系统上运行和管理容器前&#xff0c;必须先安装必要的命令行工具。使用yum命令安装container-tools模块。yum module install container-toolscontainer-tools模块包括安装多个工具的软件包&#xff0c;包括运行容器所需的podman和skopeo工具。选择容器镜像和…

程序员与ChatGPT的日常问答

程序员与ChatGPT的日常问答 本文记录下调教ChatGPT的日常。 Q&#xff1a;假设你是一个经验丰富的程序员&#xff0c;请教下__attribute__((always_inline))和inline区别是什么&#xff1f; __attribute__((always_inline)) 是 GCC 编译器的扩展属性&#xff0c;用于强制编译…