react生命周期详细介绍
目录
挂载:在组件实例被创建并插入到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()
新生命周期:
- constructor(props)
- static getDerivedStateFromProps(props,state)--替代了
componentWillReceiveProps
- render()
- 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发生变化的时候,更新stateif (type !== prevState.type) {return {type,};}// 否则,对于state不进行任何操作return null;
}
React的生命周期 - 简书
老版本中的componentWillReceiveProps()方法判断前后两个 props 是否相同,如果不同再将新的 props 更新到相应的 state 上去。这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。
这两者最大的不同就是:
在 componentWillReceiveProps 中,我们一般会做以下两件事,一是根据 props 来更新 state,二是触发一些回调,如动画或页面跳转等。
- 在老版本的 React 中,这两件事我们都需要在 componentWillReceiveProps 中去做。
- 而在新版本中,官方将更新 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的变化并返回以下类型之一:
- 通过jsx创建的react元素
- 数组或者fragments:使得render可以返回多个元素
- Portals:可以渲染子节点到不同的dom树上
- 字符串或数值类型:他们在dom中会被渲染为文本节点
- 布尔类型或者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)
新生命周期:
- static getDerivedStateFromProps(nextProps, prevState)
- shouldComponentUpdate(nextProps,nextState)
- render()
- getSnapshotBeforeUpdate(prevProps,prevState)
- 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 === trueaxios.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 使下一次渲染可以显降级 UIreturn { hasError: true };}render() {if (this.state.hasError) {// 你可以渲染任何自定义的降级 UIreturn <h1>Something went wrong.</h1>;}return this.props.children;}
}
(2)componentDidCatch:在提交阶段被调用
在后代组件抛出错误后被调用。 它接收两个参数:
error
—— 抛出的错误。info
—— 带有componentStack
key 的对象,其中包含有关组件引发错误的栈信息。
它应该用于记录错误之类的情况,下面是一个官网的示例:
class ErrorBoundary extends React.Component {constructor(props) {super(props);this.state = { hasError: false };}static getDerivedStateFromError(error) {// 更新 state 使下一次渲染可以显示降级 UIreturn { 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) {// 你可以渲染任何自定义的降级 UIreturn <h1>Something went wrong.</h1>;}return this.props.children;}
}
React 的开发和生产构建版本在 componentDidCatch()
的方式上有轻微差别。
在开发模式下,错误会冒泡至 window
,这意味着任何 window.onerror
或 window.addEventListener('error', callback)
会中断这些已经被 componentDidCatch()
捕获的错误。
相反,在生产模式下,错误不会冒泡,这意味着任何根错误处理器只会接受那些没有显式地被 componentDidCatch()
捕获的错误。
注意
如果发生错误,你可以通过调用
setState
使用componentDidCatch()
渲染降级 UI,但在未来的版本中将不推荐这样做。 可以使用静态getDerivedStateFromError()
来处理降级渲染。
react生命周期详细介绍相关推荐
- react生命周期方法介绍
react生命周期 react生命周期主要包括三个阶段:初始化阶段.运行中阶段.销毁阶段 react在不同的生命周期会触发不同的钩子函数 初始化阶段 getDefaultProps() 设置组件默认的 ...
- Android生命周期帮助类,Android Service类与生命周期详细介绍_Android_脚本之家
Android Service类与生命周期 Service是Android四大组件与Activity最相似的组件,都代表可执行的程序,区别在于Service一直在后台运行且没有用户界面. 1.Ser ...
- Vue的生命周期详细介绍
Vue的生命周期 首先,vue的生命周期是个啥? 借用官网的一句话就是:每一个vue实例从创建到销毁的过程,就是这个vue实例的生命周期.在这个过程中,他经历了从开始创建.初始化数据.编译模板.挂载D ...
- React生命周期理解
前言 如果将React的生命周期比喻成一只蚂蚁爬过一根吊绳,那么这只蚂蚁从绳头爬到绳尾,就会依次触动不同的卡片挂钩.在React每一个生命周期中,也有类似卡片挂钩的存在,我们把它称之为'钩子函数'.那 ...
- 前端React教程第二课 React生命周期设计思想
02 为什么 React 16 要更改组件的生命周期?(上) React 生命周期已经是一个老生常谈的话题了,几乎没有哪一门 React 入门教材会省略对组件生命周期的介绍.然而,入门教材在设计上往往 ...
- 浅谈 React 生命周期
浅谈 React 生命周期 浅谈 React 生命周期 旧版的生命周期 新版的生命周期 详解各个生命周期函数 constructor getDerivedStateFromProps render c ...
- 你不可不知道的React生命周期
点小蓝字加关注! 作者:kim 来源:原创 写在前面 咱今天聊的话题是React生命周期,灵感来自于最近在网上发现一篇关于react生命周期的文章,里面记录的知识点竟然与小编所get到的有出入.作为一 ...
- react生命周期_React生命周期事件
react生命周期 React class components can have hooks for several lifecycle events. React类组件可以具有多个生命周期事件的挂 ...
- 开源博客QBlog开发者视频教程:生命周期Page_Load介绍及简洁传递参数的重构方式(四)...
2019独角兽企业重金招聘Python工程师标准>>> 前言: 两三天没出视频了,主要是接下来的视频不好录制[给自己找个借口,其实顺路看了两天动漫], 当然中间也在一直想怎么录,怎么 ...
最新文章
- c++ 互斥量和条件变量
- 在记录实体log信息的时候,2个公司的区别
- 机器学习规则 (Rules of Machine Learning): 关于机器学习工程的最佳实践
- cass软件yy命令_WIN10系统中的CASS字体问题
- Java集合框架:LinkedHashMap
- assertionerror python_Python成为专业人士笔记–内置模块Modules和函数Functions
- 从0基础学Python:装饰器及练习(基础)
- Java 第五章 类的设计与包
- HTML十进制字符编号
- Rocket-chip-Cache
- c语言ip判断程序,IP判断 (C语言代码)
- 远程唤醒、WOL、Magic_Packet【转】
- 教授专栏44 | 李家涛:企业高层性别均衡,发展趋势可憧憬
- PDF.js特殊字体、水印加载不出来问题解决
- Android 源码 图形系统之请求布局
- opencv图像转换与保存
- 小白从0开始学习推荐系统
- Python绘制气象实用地图(附代码和测试数据) !
- vista下安装mysql
- html仿微信公众号底部菜单代码,模仿微信公众号底部导航菜单