react生命周期详细介绍

news2025/1/24 8:43:17

目录

 挂载:在组件实例被创建并插入到dom中时,生命周期调用顺序如下

constructor

componentWillMount

getDerivedStateFromProps

render

componentDidMount

更新:当组件的 props 或 state 发生变化时会触发更新。

componentWillReceiveProps ()

shouldComponentUpdate

componentWillUpdate

getSnapshotBeforeUpdate

componentDidUpdate

卸载:当组件从 DOM中移除时会调用如下方法:

componentWillUnmount()

错误处理:当渲染过程,生命周期,或子组件的构造函数中抛出错误时


重新学习理解react生命周期,本文主要参考链接:

React的生命周期 - 简书

React.Component – React

React新生命周期--getDerivedStateFromProps - 简书

生命周期(旧)1 - 简书

这里我没有将新旧生命周期分开写,后面标注的可以用但是不建议使用的就是被新生命周期替换的旧生命周期。图一是旧生命周期,图二是新生命周期。

首先生命周期分为三个阶段:

        挂载:已经插入真实dom

        渲染(更新):正在被重新渲染

        卸载:已经移出真实dom

 一、挂载:在组件实例被创建并插入到dom中时,生命周期调用顺序如下

旧生命周期:

        1.constructor(props)

        2.componentWillMount()-------------可以用但是不建议使用

        3.render()

        4.componentDidMount()

新生命周期:

  1. constructor(props)
  2. static getDerivedStateFromProps(props,state)--替代了componentWillReceiveProps
  3. render()
  4. componentDidMount()

(1)constructor

数据的初始化。

        接收props和context,当想在函数内使用这两个参数需要在super传入参数,当使用constructor时必须使用super,否则可能会有this的指向问题,如果不初始化state或者不进行方法绑定,则可以不为组件实现构造函数;

避免将 props 的值复制给 state!这是一个常见的错误:

constructor(props) {
 super(props);
 // 不要这样做
 this.state = { color: props.color };
}

如此做毫无必要(可以直接使用 this.props.color),同时还产生了 bug(更新 prop 中的 color 时,并不会影响 state)。

(2)componentWillMount

在挂载之前也就是render之前被调用。

        在服务端渲染唯一会调用的函数,代表已经初始化数据但是没有渲染dom,因此在此方法中同步调用 setState() 不会触发额外渲染。

(3)getDerivedStateFromProps

从props获取state。

        替代了componentWillReceiveProps,此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props。

  在初始挂载和后续更新时都会被调用,返回一个对象更新state,如果返回null就不更新;如果props传入的内容不需要影响到你的state,那么就需要返回一个null,这个返回值是必须的,所以尽量将其写到函数的末尾。

static getDerivedStateFromProps(nextProps, prevState) {
    const {type} = nextProps;
    // 当传入的type发生变化的时候,更新state
    if (type !== prevState.type) {
        return {
            type,
        };
    }
    // 否则,对于state不进行任何操作
    return null;
}

React的生命周期 - 简书

老版本中的componentWillReceiveProps()方法判断前后两个 props 是否相同,如果不同再将新的 props 更新到相应的 state 上去。这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。

这两者最大的不同就是:
在 componentWillReceiveProps 中,我们一般会做以下两件事,一是根据 props 来更新 state,二是触发一些回调,如动画或页面跳转等。

  1. 在老版本的 React 中,这两件事我们都需要在 componentWillReceiveProps 中去做。
  2. 而在新版本中,官方将更新 state 与触发回调重新分配到了 getDerivedStateFromProps 与 componentDidUpdate 中,使得组件整体的更新逻辑更为清晰。而且在 getDerivedStateFromProps 中还禁止了组件去访问 this.props,强制让开发者去比较 nextProps 与 prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在根据当前的 props 来更新组件的 state,而不是去做其他一些让组件自身状态变得更加不可预测的事情。

(4)render

class组件中唯一必须实现的方法。

render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。

当render被调用时,他会检查this.props.和this.state的变化并返回以下类型之一:

  1.   通过jsx创建的react元素
  2.   数组或者fragments:使得render可以返回多个元素
  3.   Portals:可以渲染子节点到不同的dom树上
  4.   字符串或数值类型:他们在dom中会被渲染为文本节点
  5.   布尔类型或者null:什么都不渲染

注意

        render函数是纯函数,这意味着在不修改组件state的情况下,每次调用都应该返回相同的结果,并且它不会直接和浏览器交互,如果需要和浏览器交互需要在componentDidMunt函数中或者其他生命周期函数中执行操作。

        更新过程如果 shouldComponentUpdate() 返回 false,则不会调用 render()

(5)componentDidMount

在组件挂在后(插入到dom树中)后立即调用

        可以在这里调用Ajax请求,返回的数据可以通过setState使组件重新渲染,或者添加订阅,但是要在conponentWillUnmount中取消订阅

二、更新:当组件的 props 或 state 发生变化时会触发更新。

旧生命周期:

        1.componentWillReceiveProps (nextProps)------------------可以用但是不建议使用

        2.shouldComponentUpdate(nextProps,nextState)

        3.componetnWillUpdate(nextProps,nextState----------------可以用但是不建议使用

        4.render()

        5.componentDidUpdate(prevProps,precState,snapshot

新生命周期:

  1. static getDerivedStateFromProps(nextProps, prevState)
  2. shouldComponentUpdate(nextProps,nextState)
  3. render()
  4. getSnapshotBeforeUpdate(prevProps,prevState)
  5. componentDidUpdate(prevProps,precState,snapshot

(1)componentWillReceiveProps ()

在已挂载的组件接收新的props之前调用。

通过对比nextProps和this.props,将nextProps的state为当前组件的state,从而重新渲染组件,可以在此方法中使用this.setState改变state。

  componentWillReceiveProps (nextProps) {
    nextProps.openNotice !== this.props.openNotice&&this.setState({
        openNotice:nextProps.openNotice
    },() => {
      console.log(this.state.openNotice:nextProps)
      //将state更新为nextProps,在setState的第二个参数(回调)可以打         印出新的state
  })
}

        请注意,如果父组件导致组件重新渲染,即使 props 没有更改,也会调用此方法。如果只想处理更改,请确保进行当前值与变更值的比较。

        React 不会针对初始 props 调用 UNSAFE_componentWillReceiveProps()。组件只会在组件的 props 更新时调用此方法。调用 this.setState() 通常不会触发该生命周期。

(2)shouldComponentUpdate

在渲染之前被调用,默认返回为true。

        返回值是判断组件的输出是否受当前state或props更改的影响,默认每次state发生变化都重新渲染,首次渲染或使用forceUpdate时不被调用。

他主要用于性能优化,会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性。不建议深层比较,会影响性能。如果返回false,则不会调用componentWillUpdate、render和componentDidUpdate

  • 唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新,但是不建议,建议使用 PureComponent 
  • 因为react父组件的重新渲染会导致其所有子组件的重新渲染,这个时候其实我们是不需要所有子组件都跟着重新渲染的,因此需要在子组件的该生命周期中做判断

(3)componentWillUpdate

当组件接收到新的props和state会在渲染前调用,初始渲染不会调用该方法。

        shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,不能在这使用setState,在函数返回之前不能执行任何其他更新组件的操作

此方法可以替换为 componentDidUpdate()。如果你在此方法中读取 DOM 信息(例如,为了保存滚动位置),则可以将此逻辑移至 getSnapshotBeforeUpdate() 中。

(4)getSnapshotBeforeUpdate

在最后一次渲染(提交到dom节点)之前调用,替换componetnWillUpdate

        它能在组件更改之前获取dom的节点信息(滚动位置),该方法所有返回值都会作为参数传给componentDidUpdate

和componentWillUpdate的区别

  • 在 React 开启异步渲染模式后,在 render 阶段读取到的 DOM 元素状态并不总是和 commit 阶段相同,这就导致在
    componentDidUpdate 中使用 componentWillUpdate 中读取到的 DOM 元素状态是不安全的,因为这时的值很有可能已经失效了。
  • getSnapshotBeforeUpdate 会在最终的 render 之前被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与 componentDidUpdate 中一致的。

此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。应返回 snapshot 的值(或 null)例如。

//下面参考一下官网的例子
class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 我们是否在 list 中添加新的 items ?
    // 捕获滚动​​位置以便我们稍后调整滚动位置。
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // 如果我们 snapshot 有值,说明我们刚刚添加了新的 items,
    // 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。
    //(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}

(5)componentDidUpdate:在更新之后立即调用,首次渲染不会调用,之后每次重新渲染都会被调用。

可以在该方法调用setState,但是要包含在条件语句中,否则一直更新会造成死循环

当组件更新后,可以在此处对 DOM 进行操作。如果对更新前后的props进行了比较,可以进行网络请求。(当 props 未发生变化时,则不会执行网络请求)。

componentDidUpdate(prevProps) {
  // 典型用法(不要忘记比较 props):
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

如果组件实现了 getSnapshotBeforeUpdate() 生命周期(不常用),则它的返回值将作为 componentDidUpdate() 的第三个参数 “snapshot” 参数传递。否则此参数将为 undefined。如果返回false就不会调用这个函数。

三、卸载:当组件从 DOM中移除时会调用如下方法:

(1)新旧生命周期相同:componentWillUnmount():

在组件卸载和销毁之前调用

        在这执行必要的清理操作,例如,清除timer(setTimeout,setInterval),取消网络请求,或者取消在componentDidMount的订阅,移除所有监听

有时候我们会碰到这个warning:

Can only update a mounted or mounting component. This usually      means you called setState() on an unmounted component. This is a   no-op. Please check the code for the undefined component.

原因:因为你在组件中的ajax请求返回setState,而你组件销毁的时候,请求还未完成,因此会报warning
解决方法:

componentDidMount() {
    this.isMount === true
    axios.post().then((res) => {
    this.isMount && this.setState({   // 增加条件ismount为true时
      aaa:res
    })
})
}
componentWillUnmount() {
    this.isMount === false
}
  • componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

四、错误处理:当渲染过程,生命周期,或子组件的构造函数中抛出错误时:

  • static getDerivedStateFromError(error)
  • componentDidCatch(error,info)

(1)static getDerivedStateFromError:在渲染阶段调用。

在后代组件抛出错误后被调用,他将抛出的错误作为参数,并返回一个值然后更新state

官网示例:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 更新 state 使下一次渲染可以显降级 UI
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      // 你可以渲染任何自定义的降级  UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

(2)componentDidCatch:在提交阶段被调用

在后代组件抛出错误后被调用。 它接收两个参数:

  1. error —— 抛出的错误。
  2. info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。

它应该用于记录错误之类的情况,下面是一个官网的示例:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 更新 state 使下一次渲染可以显示降级 UI
    return { hasError: 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.hasError) {
      // 你可以渲染任何自定义的降级 UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

React 的开发和生产构建版本在 componentDidCatch() 的方式上有轻微差别。

在开发模式下,错误会冒泡至 window,这意味着任何 window.onerror 或 window.addEventListener('error', callback) 会中断这些已经被 componentDidCatch() 捕获的错误。

相反,在生产模式下,错误不会冒泡,这意味着任何根错误处理器只会接受那些没有显式地被 componentDidCatch() 捕获的错误。

注意

如果发生错误,你可以通过调用 setState 使用 componentDidCatch() 渲染降级 UI,但在未来的版本中将不推荐这样做。 可以使用静态 getDerivedStateFromError() 来处理降级渲染。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/407972.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

教你如何手写一个Promise

想要源码的可以看这里&#xff0c;里面也有一些其他的知识 想要手写一个promise&#xff0c;首先就要了解promise&#xff0c;想必大家都被过一些promise的面试题&#xff0c;知道一些promise的用法&#xff0c;主要考的就是一种异步编程的思想。 了解promise 我们先来看看直…

Node.js——http模块和导出共享

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;也会涉及到服务端 &#x1f4c3;个人状态&#xff1a; 在校大学生一枚&#xff0c;已拿 offer&#xff08;秋招&#xff09; &#x1f947;推荐学习&…

uni-app 自定义下拉框

如图&#xff1a; html&#xff1a; <view class"row-item"> <view class"lable-tit">性别&#xff1a;</view> <view class"selected-all"> <view class"drop-down-box" click"btnShowHideClick…

JavaScript DOM基础

文章目录前言一、DOM 简介1.1 什么是 DOM1.2 DOM 树二、获取元素2.1 如何获取页面元素2.2 根据 ID 获取2.3 根据标签名获取2.4 通过 HTML5 新增的方法获取2.5 获取特殊元素&#xff08;body&#xff0c;html&#xff09;三、事件基础3.1 事件概述3.2 事件三要素3.3 执行事件的步…

Ant Design Pro(5)-7.高级表格ProTable

Ant Design Pro 高级表格ProTable的使用 文章目录Ant Design Pro 高级表格ProTable的使用一. 简介1. 什么是ProTable&#xff1f;2. 何时使用ProTable&#xff1f;二. 使用1. ProTable属性及使用2. ActionRef 手动触发3. Columns 列定义4. 批量操作5. 搜索表单一. 简介 1. 什么…

【Vue】父子组件通信

[Vue]父子组件通信前言父组件向子组件传值法一: props法二: $parent子组件向父组件传值$emit$emit .sync$refsv-model前言 &#x1f6a9;&#x1f6a9;&#x1f6a9; &#x1f48e;个人主页: 阿选不出来 &#x1f4a8;&#x1f4a8;&#x1f4a8; &#x1f48e;个人简介: 一名…

【Javaweb】会话跟踪技术CookieSession

学习目录前言一.会话引入二.Cookie1.Cookie的理解2.Cookie生命周期3.Cookie有效路径4.Cookie使用细节三.Session1.Session基本原理2.Session的理解3.Session基本使用4.Session底层5.Session生命周期前言 纸上得来终觉浅&#xff0c;绝知此事要躬行 一.会话引入 什么是会话&a…

“Property or method “***“ is not defined on the instance but referenced during render.”报错的原因及解决方案

报错问题&#xff1a; 在使用vue-cli运行项目的过程中&#xff0c;在VScode中不报错&#xff0c;但在浏览器调试工具中发出 [Vue warn]: Property or method "******" is not defined on the instance but referenced during render. Make sure that this propert…

vue-day01 使用cdn引入使用

vue-day01vue?vue简明例子模板语法1. 使用{{}} Mustache语法将数据绑定到对应的实例2.使用 v-once指令3.v-html指令4.v-bind指令和v-on指令5.动态参数&#xff0c;修饰符&#xff0c;指令缩写动态参数修饰符指令缩写vue? Vue 是一套用于构建用户界面的渐进式框架。与其它大型…

前端不使用 i18n,如何优雅的实现多语言?

前言&#xff1a; 关于ERP管理系统的多语言&#xff0c;或者其他应用的多语言一直是我们比较麻烦的问题&#xff0c;大部分是使用 i18n 在代码里进行配置&#xff0c;如果想要修改语言就要自己去改代码&#xff01; 今天我们分享一下如何不使用 i18n 去实现多语言&#xff0c;用…

web前端面试高频考点——Vue的基本使用(一文掌握Vue最基础的知识点)

系列文章目录 内容参考链接Vue基本使用Vue的基本使用&#xff08;一文掌握Vue最基础的知识点&#xff09;Vue通信和高级特性Vue组件间的通信及高级特性&#xff08;多种组件间的通信、自定义v-model、nextTick、插槽&#xff09;Vue高级特性Vue的高级特性&#xff08;动态组件…

ES6遍历方法,forEach、for...in,for..of

前言 js中遍历方法很多&#xff0c;在ES6新特性中出现了很多新的遍历方法&#xff0c;使遍历数组和对象更加方便&#xff0c;下面开始列举各种方法。 1.遍历对象 1.1.for…in…循环遍历对象自身和继承的可枚举的属性&#xff08;不包括Symbol&#xff0c;因为symbol的实例是…

微信小程序开发入门与实战(数据、事件、条件)

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; 微信小程序 &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f4…

layui 的数据表单的defaultToolbar参数中筛选列,图标,打印,三个功能,调用单独拿出使用

项目场景&#xff1a; 参数之defaultToolbar&#xff1a; 在使用layui开发的过程中&#xff0c;常常会用到 数据表单 这一关键模块&#xff0c;在这里讲一下defaultToolbar:[filter,exports print]-------“头部工具栏右侧图标”&#xff0c;如何将这三个按钮调用出来&#x…

【vscode】vscode常用插件介绍

1、Angular Snippets&#xff08;angular片段&#xff09; 这个扩展为 TypeScript 和 HTML 添加了 Angular 的代码片段。 2、Auto Close Tag&#xff08;自动闭合标签&#xff09; 自动添加 HTML/XML 关闭标记。 3、Auto Rename Tag&#xff08;自动重命名标签&#xff09; 自…

Three.js基础入门系列(九)--导入3D模型

先来学习今天的知识——Three.js导入3D模型 复杂的3D模型&#xff08;比如制作一个飞机模型&#xff09;一般都是用第三方建模工具生成&#xff0c;然后加载到Three.js中。 01 常用建模制作工具 3Dmax 链接地址&#xff1a;https://www.autodesk.com.cn/products/3ds-max/over…

启动vue-element-admin 安装npm install报错npm ERR! code 128npm ERR! An unknown git error occurre

使用vue-element-admin前端项目&#xff0c;前提是有nodejs环境&#xff0c;对于此环境的安装可以参考网上的博客。此博客用于记录启动项目以及遇到的问题、并解决问题的过程。1、介绍vue-element-admin是基于element-ui 的一套后台管理系统集成方案 。功能&#xff1a;https:/…

Vue基础教程(下篇)

&#x1f60a;作者简介&#xff1a;大家好&#xff0c;我是是你的大头呢&#xff0c;一名大三学生&#xff0c;考研备考中。让我们一起加油&#xff0c;一起努力&#xff01; &#x1f9d1;‍&#x1f4bb;博客主页&#xff1a;是你的大头呢 &#x1f970;欢迎关注&#x1f38a…

javascript 中搜索数组的四种方法

前端经常要通过 javaScript 来处理数组中的数据&#xff0c;其中就包括检查数组中是否包含满足特定搜索条件的单个或者多个值&#xff0c;这就需要我们关于用于确认的布尔值、数组中值得位置索引或包含所有搜索结果的单独数组等。 在 ECMAScript6 之前&#xff0c;最常用的方法…

Vue中 this.$set的用法

一、this.$set能够实现什么功能 官方解释&#xff1a;向响应式对象中添加一个属性&#xff0c;并确保这个新属性同样是响应式的&#xff0c;且触发视图更新。它必须用于向响应式对象上添加新属性&#xff0c;因为 Vue无法探测普通的新增属性 (比如 this.myObject.newProperty …