React生命周期原理与用法踩坑笔记


Posted in Javascript onApril 28, 2020

本文实例讲述了React生命周期原理与用法。分享给大家供大家参考,具体如下:

React生命周期

生命周期概览

生命周期的状态

组件的生命周期可分成三个状态:

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲
  • Unmounting:已移出真实 DOM
  • componentWillMount 在渲染前调用,在客户端也在服务端。

生命周期介绍

componentDidMount :

在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。

componentWillReceiveProps

在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。

shouldComponentUpdate

返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。

可以在你确认不需要更新组件时使用。

componentWillUpdate

在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。

componentDidUpdate

在组件完成更新后立即调用。在初始化时不会被调用。

componentWillUnmount

在组件从 DOM 中移除之前立刻被调用。

代码示意

class Content extends React.Component {
 componentWillMount() {
   console.log('Component WILL MOUNT!')
 }
 componentDidMount() {
    console.log('Component DID MOUNT!')
 }
 componentWillReceiveProps(newProps) {
    console.log('Component WILL RECEIVE PROPS!')
 }
 shouldComponentUpdate(newProps, newState) {
    return true;
 }
 componentWillUpdate(nextProps, nextState) {
    console.log('Component WILL UPDATE!');
 }
 componentDidUpdate(prevProps, prevState) {
    console.log('Component DID UPDATE!')
 }
 componentWillUnmount() {
     console.log('Component WILL UNMOUNT!')
 }

React16.3生命周期

安装

在创建组件的实例并将其插入DOM时,将按以下顺序调用这些方法:

constructor()

React组件的构造函数在安装之前被调用。在实现React.Component子类的构造函数时,应该super(props)在任何其他语句之前调用。否则,this.props将在构造函数中未定义,这可能导致错误。

通常,在React中,构造函数仅用于两个目的:

通过分配对象来初始化本地状态this.state。

将事件处理程序方法绑定到实例。

不应该打电话setState()给constructor()。相反,如果您的组件需要使用本地状态,请直接在构造函数中指定初始状态this.state。

构造函数是his.state直接分配的唯一位置。在所有其他方法中,需要使用this.setState()。

static getDerivedStateFromProps()

getDerivedStateFromProps在调用render方法之前调用,无论是在初始安装还是后续更新。它应该返回一个更新状态的对象,或者返回null以不更新任何状态。

render()

render()方法是类组件中唯一必需的方法。

调用时,它应检查this.props并this.state返回以下类型之一:

  • React elements。通常通过JSX创建。
  • Arrays and fragments。让您从渲染中返回多个元素。有关更多详细信息,请参阅片段文档。
  • Portals。
  • 字符串和数字。它们在DOM中呈现为文本节点。
  • 布尔或null。什么都没有。

该render()函数应该无状态的,这意味着它不会修改组件状态,每次调用时都返回相同的结果,并且它不直接与浏览器交互。

如果您需要与浏览器进行交互,请执行componentDidMount()或其他生命周期方法。保持render()纯粹使组件更容易思考。

如果shouldComponentUpdate()返回false,则render()不会被调用

componentDidMount()

  • componentDidMount()在安装组件(插入树中)后立即调用。需要DOM节点的初始化应该放在这里。如果需要从远程端点加载数据,这是实例化网络请求的好地方。
  • 此方法是设置任何订阅的好地方。如果您这样做,请不要忘记取消订阅componentWillUnmount()。
  • 您可以在componentDidMount()立即使用this.setState()。它将触发额外的渲染,但它将在浏览器更新屏幕之前发生。这保证即使render()在这种情况下将被调用两次,用户也不会看到中间状态。请谨慎使用此模式,因为它通常会导致性能问题。在大多数情况下,您应该能够分配初始状态constructor()。但是,当您需要在渲染依赖于其大小或位置的东西之前测量DOM节点时,可能需要对模态和工具提示等情况进行处理。

这些方法被认为是遗留的,应该在新代码中避免它们:

UNSAFE_componentWillMount()

更新

props or state 的更改可能导致更新。重新渲染组件时,将按以下顺序调用这些方法:

static getDerivedStateFromProps()
render()
getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate(prevProps, prevState)

getSnapshotBeforeUpdate()在最近呈现的输出被提交到例如DOM之前调用。它使得组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

此用例并不常见,但它可能出现在需要以特殊方式处理滚动位置的聊天线程等UI中。

官网的例子

class ScrollingList extends React.Component {
 constructor(props) {
  super(props);
  this.listRef = React.createRef();
 }

 getSnapshotBeforeUpdate(prevProps, prevState) {
  // Are we adding new items to the list?
  // Capture the scroll position so we can adjust scroll later.
  if (prevProps.list.length < this.props.list.length) {
   const list = this.listRef.current;
   return list.scrollHeight - list.scrollTop;
  }
  return null;
 }

 componentDidUpdate(prevProps, prevState, snapshot) {
  // If we have a snapshot value, we've just added new items.
  // Adjust scroll so these new items don't push the old ones out of view.
  // (snapshot here is the value returned from getSnapshotBeforeUpdate)
  if (snapshot !== null) {
   const list = this.listRef.current;
   list.scrollTop = list.scrollHeight - snapshot;
  }
 }

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

componentDidUpdate()

componentDidUpdate()更新发生后立即调用。初始渲染不会调用此方法。

将此作为在更新组件时对DOM进行操作的机会。只要您将当前道具与之前的道具进行比较(例如,如果道具未更改,则可能不需要网络请求),这也是进行网络请求的好地方。

componentDidUpdate(prevProps) {
 // Typical usage (don't forget to compare props):
 if (this.props.userID !== prevProps.userID) {
  this.fetchData(this.props.userID);
 }
}

componentDidUpdate()但要注意,必须在一个条件下被包裹就像上面的例子中,否则会导致无限循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。

componentDidUpdate():如果shouldComponentUpdate()返回false,则不会被调用。

这些方法被认为是遗留的,您应该在新代码中避免它们:

UNSAFE_componentWillUpdate()

UNSAFE_componentWillReceiveProps()

卸载

从DOM中删除组件时调用此方法:

componentWillUnmount()

componentWillUnmount()在卸载和销毁组件之前立即调用。在此方法中执行任何必要的清理,例如使计时器无效,取消网络请求或清除在其中创建的任何订阅componentDidMount()。

不应该调用setState(),componentWillUnmount()因为组件永远不会被重新呈现。卸载组件实例后,将永远不会再次安装它。

错误处理

在渲染期间,生命周期方法或任何子组件的构造函数中发生错误时,将调用这些方法。

static getDerivedStateFromError()

static getDerivedStateFromError(error)

在后代组件抛出错误后调用此生命周期。它接收作为参数抛出的错误,并应返回值以更新状态。

componentDidCatch()

componentDidCatch(error, info)

在后代组件抛出错误后调用此生命周期。它接收两个参数:

error - 抛出的错误。

info- componentStack包含键的对象,其中包含有关哪个组件引发错误的信息。

如果发生错误,可以componentDidCatch()通过调用呈现回退UI setState,但在将来的版本中将不推荐使用。使用static getDerivedStateFromError()处理回退,而不是渲染。

componentDidCatch()在“提交”阶段被调用,因此允许副作用。它应该用于记录错误之类的事情:

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

 static getDerivedStateFromError(error) {
  // Update state so the next render will show the fallback UI.
  return { hasError: true };
 }

 componentDidCatch(error, info) {
  // Example "componentStack":
  //  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) {
   // You can render any custom fallback UI
   return <h1>Something went wrong.</h1>;
  }
  return this.props.children; 
 }
}

希望本文所述对大家react程序设计有所帮助。

Javascript 相关文章推荐
javascript 读取xml,写入xml 实现代码
Jul 10 Javascript
js 字符串操作函数
Jul 25 Javascript
jquery插件制作 表单验证实现代码
Aug 17 Javascript
一个html5播放视频的video控件只支持android的默认格式mp4和3gp
May 08 Javascript
JavaScript中的对象与JSON
Jul 03 Javascript
使用jQuery.Qrcode插件在客户端动态生成二维码并添加自定义Logo
Sep 01 Javascript
js canvas仿支付宝芝麻信用分仪表盘
Nov 16 Javascript
JavaScript之RegExp_动力节点Java学院整理
Jun 29 Javascript
如何理解Vue的render函数的具体用法
Aug 30 Javascript
JQuery获取可视区尺寸和文档尺寸及制作悬浮菜单示例
May 14 jQuery
新手入门js闭包学习过程解析
Oct 08 Javascript
AngularJS动态生成select下拉框的方法实例
Nov 17 Javascript
js最全的数组的降维5种办法(小结)
Apr 28 #Javascript
JS数组降维的实现Array.prototype.concat.apply([], arr)
Apr 28 #Javascript
React中Ref 的使用方法详解
Apr 28 #Javascript
在Webpack中用url-loader处理图片和字体的问题
Apr 28 #Javascript
react PropTypes校验传递的值操作示例
Apr 28 #Javascript
vue 百度地图(vue-baidu-map)绘制方向箭头折线实例代码详解
Apr 28 #Javascript
Vue + Scss 动态切换主题颜色实现换肤的示例代码
Apr 27 #Javascript
You might like
php删除txt文件指定行及按行读取txt文档数据的方法
2017/01/30 PHP
Laravel 手动开关 Eloquent 修改器的操作方法
2019/12/30 PHP
Yii 框架入口脚本示例分析
2020/05/19 PHP
用javascript实现改变TEXTAREA滚动条和按钮的颜色,以及怎样让滚动条变得扁平
2007/04/20 Javascript
图片连续滚动代码[兼容IE/firefox]
2009/06/11 Javascript
javascript语言结构小记(一)
2011/09/10 Javascript
Dom操作之兼容技巧分享
2011/09/20 Javascript
Jquery实现简单的动画效果代码
2012/03/18 Javascript
为什么要在引入的css或者js文件后面加参数的详细讲解
2013/05/03 Javascript
JS冒泡事件的快速解决方法
2013/12/16 Javascript
setTimeout自动触发一个js的方法
2014/01/15 Javascript
jQuery使用drag效果实现自由拖拽div
2015/06/11 Javascript
JavaScript中的Repaint和Reflow用法详解
2015/07/27 Javascript
跟我学习javascript的call(),apply(),bind()与回调
2015/11/16 Javascript
AngularJS实现的2048小游戏功能【附源码下载】
2018/01/03 Javascript
Angularjs Promise实例详解
2018/03/15 Javascript
Vuex的基本概念、项目搭建以及入坑点
2018/11/04 Javascript
Async/Await替代Promise的6个理由
2019/06/15 Javascript
javascript中的this作用域详解
2019/07/15 Javascript
vuejs移动端实现div拖拽移动
2019/07/25 Javascript
vue 数据遍历筛选 过滤 排序的应用操作
2020/11/17 Javascript
[00:33]2016完美“圣”典风云人物:BurNIng宣传片
2016/12/10 DOTA
python使用点操作符访问字典(dict)数据的方法
2015/03/16 Python
python实现用户登录系统
2016/05/21 Python
Python爬虫将爬取的图片写入world文档的方法
2018/11/07 Python
python调用java的jar包方法
2018/12/15 Python
python实现井字棋小游戏
2020/03/04 Python
配置python的编程环境之Anaconda + VSCode的教程
2020/03/29 Python
解决Windows下python和pip命令无法使用的问题
2020/08/31 Python
Linux文件系统类型
2012/09/16 面试题
环保建议书300字
2014/05/14 职场文书
食品安全责任书范本
2015/05/09 职场文书
怎样写观后感
2015/06/19 职场文书
如何利用map实现Nginx允许多个域名跨域
2021/03/31 Servers
通过T-SQL语句创建游标与实现数据库加解密功能
2022/03/16 SQL Server
python中使用redis用法详解
2022/12/24 Redis