![3e14839940ca4f299d14e3780f31b293.png](https://i-blog.csdnimg.cn/blog_migrate/b78032918d57a1154808a0e185893859.jpeg)
![3558d7c71c694082f5b1fc3d3215e6dc.png](https://i-blog.csdnimg.cn/blog_migrate/27a7b270bb57eb947eb623e0be30f915.jpeg)
写在前边
这是一片记录react生命周期的文章。博主最近在重读react官网,想对react有更深度的理解。如果你同样对react这个优秀的框架抱有兴趣,欢迎联系我一同探讨!!文中有描述含混不清和错误的地方,望不吝赐教,直接指出
文末附有验证生命周期API先后顺序的demo
QQ: 272473132
github: https:// github.com/CregskiN
知乎文章的代码编写体验是在不敢恭维,如果实在影响阅读,请移步
关于react生命周期的总结 - 个人文章 - SegmentFault 思否segmentfault.com![81687cadece0602ca501fce42b857e90.png](https://i-blog.csdnimg.cn/blog_migrate/88e96bbf44e35b5b0218559a3ed50822.png)
1. 基础概念
Mount、Update、Unmount
- Mounting:组件初次渲染
- Updating:因某些原因,组件需要更新
- Unmounting:组件卸载。即他的父组件的render()函数中不再return他
渲染阶段、预提交阶段、提交阶段
- Render phase:react负责将JSX渲染为DOM对象(仅渲染,不更新页面)
一旦state或props改变,Render phase阶段将被强制重新执行(具体次数无法预计)。所以尽量不要Render phase更新state或props。
- Pre-commit phase:react渲染完DOM,预提交阶段,在这里,可以读取DOM信息
- Commit phase:react渲染并完成DOM更新
官方建议:仅在Commit phase执行副作用、state更新
2. Mounting阶段
Render phase
constructor()
- 初始化state、props
- 初始化state不要用props.color,可以直接用this.props.color
- 为事件处理 绑定this
static getDerivedStateFromProps(props, state)
- 用处罕见:派生状态组件,即state在任何时候都取决于prop
不建议使用派生组件,会导致受控于非受控含混不清,state混乱 - return newState 返回对象以更新state,若返回null,不更新任何内容(无法使用this.state修改state)
- 用处罕见:派生状态组件,即state在任何时候都取决于prop
render()
当render
被调用时,它会检查this.props
和this.state
的变化并返回以下类型之一:
- React 元素。通常通过 JSX 创建。例如,
会被 React 渲染为 DOM 节点,
会被 React 渲染为自定义组件,无论是还是
均为 React 元素。 - 数组或 fragments。 使得 render 方法可以返回多个元素。欲了解更多详细信息,请参阅 fragments 文档。
- Portals。可以渲染子节点到不同的 DOM 子树中。欲了解更多详细信息,请参阅有关 portals 的文档
- 字符串或数值类型。它们在 DOM 中会被渲染为文本节点
- 布尔类型或
null
。什么都不渲染。(主要用于支持返回test &&
的模式,其中 test 为布尔类型。)
Pre-commit phase
Commit phase
componentDidMount()
- this.setState() 触发额外渲染,但会在浏览器更新屏幕之前
- 副作用(side effect)
3. Updating阶段
当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:
Render phase
static getDerivedStateFromProps()
shouldComponentUpdate(nextProps, nextState)
- return false ? 不调用 Updating阶段的render() : 调用 Updating阶段的render();
render()
Pre-commit phase
getSnapshotBeforeUpdate(prevProps, prevState)
- 在以下场景调用:
- 想要在组件改变之前获取DOM信息,如滚动位置
- 在以下场景调用:
博主疑问:
为什么只有Updating阶段有getSnapshotBeforeUpdate而Mounting阶段没有?
是因为在Mounting阶段读取DOM的需求吗?
还是说官方建议Mounting阶段读取DOM的逻辑放到componentDidMount执行?
Commit phase
componentDidUpdate(prevProps, prevState, snapshot)
this.setState() 额外渲染,影响性能!! 而且一定用if包裹,否则会死循环
componentDidUpdate(prevProps) {
// 典型用法(不要忘记比较 props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
4. Unmounting阶段
当组件从 DOM 中移除时会调用如下方法:
Render phase
Pre-commit phase
Commit phase
componentWillUnmount()
5. other lifecycle
错误处理
当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:
Render phase
static getDerivedStateFromError(error)
- return newState;
Commit phase
componentDidCatch(error, info)
- error:Error实例
- info:React.ErrorInfo 包含错误栈信息
关于getDerivedStateFromError和componentDidCatch的用法,请见我另一篇文章:
CregskiN:react之错误边界(Error Boundaries)zhuanlan.zhihu.com![1150be35423efb7686f07b5bb4d41ea8.png](https://i-blog.csdnimg.cn/blog_migrate/5f623990f0672d242ce5a080fa280910.png)
父组件Lifecycle.tsx
import React, { Component } from 'react';
import CanUnmount from './CanUnmount';
interface LifecycleProps { };
interface LifecycleState {
counter: number;
};
function tableLog(logName: string, obj: any) {
if (obj !== null && obj !== undefined) {
if (typeof obj === 'object' && obj.length) {
console.log(logName);
console.table(obj);
}
}
}
class lifecycle extends Component<LifecycleProps, LifecycleState> {
handleAdd() {
this.setState((state, props) => ({
counter: state.counter + 1
}))
}
handleLess() {
this.setState((state, props) => ({
counter: state.counter - 1
}))
}
handleReset() {
this.setState((state, props) => ({
counter: 0
}))
}
// Mounting
constructor(props: LifecycleState) {
super(props);
this.state = {
counter: 0,
};
console.group({ lifecycle: 'constructor' });
console.table(this.state)
console.groupEnd();
this.handleAdd = this.handleAdd.bind(this);
this.handleLess = this.handleLess.bind(this);
this.handleReset = this.handleReset.bind(this);
}
static getDerivedStateFromProps(props: LifecycleProps, state: LifecycleState) {
// render-phase 获得来自副组件的props派生
console.group({ lifecycle: 'getDerivedStateFromProps' });
tableLog('props', props);
tableLog('state', state);
console.groupEnd();
return null;
}
render() {
console.group({ lifecycle: 'render' });
console.groupEnd();
const { counter } = this.state;
const { handleAdd, handleLess, handleReset } = this;
if (counter < 3) {
return (
<div>
{counter}
<button onClick={handleAdd}>+1</button>
<button onClick={handleLess}>-1</button>
</div>
)
} else {
return (
<div>
{counter}
<button onClick={handleReset}>reset</button>
<CanUnmount />
</div>
)
}
}
componentDidMount() {
console.group({ lifecycle: 'componentDidMount' });
console.log('Mounting finished')
console.groupEnd();
console.log('n');
}
// Updating
// static getDerivedStateFromProps
shouldComponentUpdate(nextProps: LifecycleProps, nextState: LifecycleState) {
console.group({ lifecycle: 'shouldComponentUpdate' });
tableLog('nextProps', nextProps);
tableLog('nextState', nextState);
console.groupEnd();
if (this.state.counter !== nextState.counter) {
return true;
}
return false;
}
// render
getSnapshotBeforeUpdate(prevProps: LifecycleProps, prevState: LifecycleState) {
console.group({ lifecycle: 'getSnapshotBeforeUpdate' });
tableLog('prevProps', prevProps);
tableLog('prevState', prevState);
console.log('getSnapshotBeforeUpdate finished');
console.groupEnd();
return { snapshot: 'ss' };
}
componentDidUpdate(prevProps: LifecycleProps, prevState: LifecycleState, snapshot: any) {
console.group({ lifecycle: 'componentDidUpdate' });
tableLog('prevProps', prevProps);
tableLog('prevState', prevState);
tableLog('snapshot', snapshot);
console.log('Update finished');
console.groupEnd();
console.log('n');
}
// Upmounting
componentWillUnmount() {
console.group({ lifecycle: 'componentWillUnmount' });
console.log('Unmounting finished');
console.groupEnd();
console.log('n');
}
}
export default lifecycle;
子组件 CanUnmoun.tsx
import React, { Component } from 'react';
interface CanUnmounProps { };
class CanUnmoun extends Component {
componentWillUnmount() {
console.group({ lifecycle: 'CanUnmount componentWillUnmount' });
console.log('CanUnmount Unmounting finished');
console.groupEnd();
console.log('n');
}
render() {
return (
<div>
Component CanUnmoun
</div>
)
}
}
export default CanUnmoun;
Reference
React.Component
快速了解React的新功能Suspense和Hooks