这篇文章所包含的内容如下,方便检索:
react生命周期
正文
react的生命周期
上一回我们说到react的生命周期有分为常用以及不常用的几个生命周期,现在我们说一下关于生命周期如何去使用以及其调用顺序。
首先回顾下生命周期图谱
react的生命周期主要分为三个状态,分别是:挂载时
、更新时
、卸载时
,而对于挂载和更新
又会分为render阶段
、pre-commit阶段
以及commit阶段
。
其实从图中就可以一目了然,'render’阶段其实是可以随时被打断
的,也就意味着可能会进行多次的render。
文字太多不好,直接上代码
创建俩个组件,一个是父组件,一个是子组件,父组件可以决定子组件展示/隐藏。
import React from 'react';
import Child from "./Child";
class Father extends React.Component {
constructor(props) {
super(props);
this.state = {
showChild: true
}
console.log('Father.constructor');
}
static getDerivedStateFromProps(props, state) {
console.log('Father.getDerivedStateFromProps');
return state
}
componentDidMount() {
console.log('Father.componentDidMount');
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('Father.getSnapshotBeforeUpdate');
// getSnapshotBeforeUpdate钩子return的数据会被
// componentDidUpdate的第三个参数接收
return null;
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
return true;
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('Father.componentDidUpdate');
}
componentWillUnmount() {
console.log('Father.componentWillUnmount');
}
render() {
console.log('Father.render');
const {showChild} = this.state
return <div>
Father <br/>
<button onClick={() => {
console.log('点击' + (showChild ? '隐藏' : '展示') + '子元素btn');
this.setState({showChild: !showChild})
}}>{showChild ? '隐藏' : '展示'} -》 子元素
</button>
{showChild && <Child/>}
</div>
}
}
export default Father;
子组件
import React from 'react';
class Child extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
a: true
}
console.log('Child.constructor');
}
static getDerivedStateFromProps(props, state) {
console.log('Child.getDerivedStateFromProps');
return state
}
componentDidMount() {
console.log('Child.componentDidMount');
}
componentWillUnmount() {
console.log('Child.componentWillUnmount');
}
render() {
console.log('Child.render');
return <div>
Child
</div>
}
}
export default Child;
对于react来说,父组件嵌套子组件,在默认都展示的情况下,初次的展示逻辑为:
① Father.constructor
② Father.getDerivedStateFromProps
③ Father.render
④ Child.constructor
⑤ Child.getDerivedStateFromProps
⑥ Child.render
⑦ Child.componentDidMount
⑧ Father.componentDidMount
看起来非常的明显且眼熟,是不是跟vue的生命周期的挂载形式很像,vue是父组件beforeCreate、created、beMounted后 子组件优先走到mounted,父组件才mounted
所以react在挂载阶段是先父组件render 然后子组件render以及commit后,父组件再commit
。
点击切换按钮将子组件隐藏,会触发父组件更新以及子组件卸载
父组件更新也是依次触发render然后等子组件完事再回到父组件commit。
所以生命周期的顺序执行其实根据前面的生命周期图谱
就可以一目了然了。
react的生命周期的应用
只有
类组件
才有生命周期,函数式组件我们可以使用react hook
模拟绝大多数的生命周期,单纯的函数式组件是没有生命周期的。
constructor
在react的class组件中,constructor可写可不写
// ①
constructor(props) { // props是父组件传递下来的
super(props);
this.state = {
a: 1
}
// 此处可以给方法绑定this
// 给对应方法添加防抖/节流功能
// 获取props给对应的state属性赋值
// ...
}
// ② 等同于
state = {
a: 1
}
getDerivedStateFromProps
static getDerivedStateFromProps(props, state) {
// 返回null表示什么都不做
// 返回一个对象来更新state
// 当前方法不能调用this
// 常见用途:判断props|state是否符合需求,返回对应state
// 按需筛选数据上报
// ....
return null
}
render
// 在render里面能够获取当前组件的state以及props
const {a} = this.state;
const {b} = this.props;
// 能够写方法,仅在当前render内部使用,常用于结合jsx做判断
function typeOfShow(type) {
return type === '1' ? '红色' : '黄色'
}
// ① 返回null或者返回空标签或者数字字符串或者布尔值
render(
// return null // 但是不会渲染
// return <></>
// return 123
// return 'test'
// return true // 但是不会渲染
)
// ② 返回jsx
render(
return <div>
jsx-{typeOfShow(1)}
</div>
)
componentDidMount
componentDidMount() {
// 常在此处进行ajax请求或者获取dom
console.log('componentDidMount');
console.log(this)
// axios.get('')
this.timer = setInterval(() => {
console.log('in.')
}, 10000)
}
componentWillUnmount
componentWillUnmount() {
// 常在此生命周期进行副作用的清除以及异步请求的打断等...
clearInterval(this.timer);
}
getSnapshotBeforeUpdate
getSnapshotBeforeUpdate(prevProps, prevState) {
// 在最近一次渲染输出(提交到 DOM 节点)之前调用
// 不常用的生命周期,用于特殊需求中
console.log('getSnapshotBeforeUpdate');
// getSnapshotBeforeUpdate钩子return的数据会被
// componentDidUpdate的第三个参数接收
return null;
}
componentDidUpdate
componentDidUpdate(prevProps, prevState, snapshot) {
// state更新后触发,可在此处进行dom操作异步请求等
// 第三个参数是getSnapshotBeforeUpdate返回的
console.log('componentDidUpdate');
}
shouldComponentUpdate
常用来做性能优化的生命周期,return false即可阻止渲染
首次渲染
或使用forceUpdate()
时不会调用该方法
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log('shouldComponentUpdate');
return true;
}
错误边界
getDerivedStateFromError
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以显降级 UI
return { hasError: true };
}
componentDidCatch
componentDidCatch(error, info) {
// "组件堆栈" 例子:
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
logComponentStackToMyService(info.componentStack);
}
直接贴出官网的demo
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;
}
}
其他过时的生命周期现在都被标记为UNSAFE,也不建议使用
UNSAFE_componentWillMount
UNSAFE_componentWillReceiveProps
UNSAFE_componentWillUpdate
项目demo我会上传到GitHub,大家有需要可自行download
参考链接:
react
react lifecycle
GitHub-demo