先看图
图片地址
各个阶段生命周期函数
constructor()
官方文档链接
构造函数,在组件被实例化是首先被调用的方法,通常用于完成一下几个任务:
- 初始化组件的状态(state):可以在
constructor()
方法中初始化组件的状态,以便在组件的生命周期中使用他们。 - 绑定
事件处理函数
:可以在constructor()
方法中绑定事件处理函数,以便在组件渲染时使用。这样做可以避免组件每次渲染时都重新创建事件处理函数,从而提高性能。 - 执行必要的继承操作:如果您想在组件中继承另一个类的属性和方法,可以在 constructor() 方法中调用 super(props) 方法,以确保正确地继承父类的所有属性和方法。例如扩展React.Component。
如果您想要创建一个自定义组件,并且需要访问 React.Component 类中的属性和方法,那么您可以通过继承 React.Component 类来实现。在子类的 constructor() 方法中,需要调用 super(props) 方法,以确保正确地继承 React.Component 类的所有属性和方法。
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
// 初始化组件的状态
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
export default MyComponent;
注意:constructor() 方法中不应该执行与组件状态无关的操作,例如发起网络请求或进行其他副作用。这是因为在 constructor() 方法被调用时,组件的 DOM 节点还没有被创建,因此可能会导致意外的错误。如果在 constructor() 方法中尝试调用 this.setState() 方法,将会引发错误,因为在这个阶段,组件的状态还没有被初始化。
static getDerivedStateFromProps(nextProps, state)
官方文档链接
在调用render
方法之前调用。从props中获得state
- 参数:第一个参数为即将更新的
props
,第二个参数为上一个状态的state
,可以比较props
和state
来加一些限制条件,防止无用的state更新。 - 返回值:返回一个对象来更新
state
,如果返回null
则不更更新任何内容。 getDerivedStateFromProps
是一个静态函数,不能使用this,也就是只能作一些无副作用的操作。
getDerivedStateFromProps
这个函数是用来替代componentWillReceiveProps
componentWillReceiveProps
官方文档链接
在初始化render
的时候不会执行,在组件接受到新的props
时被触发,一般用于父组件状态更新时子组件的重新渲染。这个方法仅在父组件重新渲染时触发,而不是在内部调用setState
时触发。
在这个函数中可以根据this.props
和nextprops
的变化,通过调用this.setState
来更新组件。旧的props可以通过this.props
来获取,在这个生命周期函数中更新state是安全的,并不会额外触发render
。
官网中已经不建议使用个方法。可以使用getDerivedStateFromProps
和componentDidUpdate
这两个生命周期函数来替代。
例如:
需要从props中更新state时使用getDerivedStateFromProps
生命周期来替代
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.content !== prevState.arrangedCommandMethod.content) {
return {
arrangedCommandMethod: {
...prevState.arrangedCommandMethod,
content: [...(nextProps.content ?? [])],
}
};
}
return null;
}
需要使用旧的props来做一些事情就用componentDidUpdate
componentDidUpdate(prevProps: PropsType, prevState: StateType) {
if (prevProps.content !== this.props.content) {
// .....
}
}
render()
官方文档链接
render()
方法是class组件中唯一必须实现的方法,用于渲染dom。必须要保证render()
函数为纯函数,这意味着不能再render里面修改state,否则会触发死循环导致内存崩溃。
componentDidMount()
官方文档链接
componentDidMount()
会在组件挂载后(插入 DOM 树中)立即调用,该声明周期是发送网络请求、添加监听事件监听方法的好时机。可以在此声明周期函数中直接调用setState()
。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。
通常,你应该在 constructor() 中初始化 state。如果你的渲染依赖于 DOM 节点的大小或位置,可以使用此声明周期函数。
在该生命周期中setState
导致渲染两次的问题,可以使用函数式组件的useEffect来解决
例如:
import { useState, useEffect } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
// 发送网络请求获取数据
const fetchData = async () => {
const result = await fetch('https://example.com/data');
const data = await result.json();
setData(data);
};
fetchData();
}, []); // 第二个参数是一个空数组,表示只在组件挂载时执行一次
// 在组件中渲染数据
return (
<div>
{data ? (
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
) : (
<p>Loading...</p>
)}
</div>
);
}
shouldComponentUpdate(nextProps, nextState)
官方文档链接
当props
或state
发生变化时,会在render()
之前调用,默认返回值为true,即重新渲染。首次渲染或者forceUpdate()
时不会调用该方法。
常用做性能优化的手段,可以使用内置的PureComponent
组件来代替自己重写shouldComponentUpdate()
方法。PureComponent
默认是浅比较,会比较当前组件的props
和state
是否与上一次渲染时的值相同,相同则返回false不更新,否则返回true。
浅比较只会比较对象的引用是否相同,不会递归比较对象的内部属性。如果在props
或state
中包含了引用类型的数据,那么默认的浅比较可能就无法满足更新的需求,需要自己重写shouldComponentUpdate()
方法,进行深层次比较。
不建议在shouldComponentUpdate()
中进行深层次比较或者使用JSON.stringify()
。非常影响效率。应该尽量避免使用深层次的 state 结构,因为这样会增加比较的复杂度。
不能在shouldComponentUpdate()
中调用setState
,会导致死循环。
getSnapshotBeforeUpdate
在最近一次渲染输出(提交到DOM节点)之前调用。它使得组件能在发生变更之前从DOM中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为参数传递给componentDidUpdate()
。
此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。
官方给的例子已经很明白了。
componentDidUpdate
会在更新后立即调用。首次渲染不能执行此方法。
包含三个参数,第一个参数是上一次props值,第二个是上一次state值。如果组件实现了getSnapshotBeforeUpdate()
生命周期,第三个是该函数的返回值。
可以执行setState()
,但是必须把他包裹在一个条件语句里,否则会造成死循环。
componentWillUnmount()
在组件即将被卸载或销毁时进行调用。是清理必要操作的好时机。如,监听事件、清理DOM元素、清理定时器等操作。
注:StrictModel导致渲染两次问题。
详细官方文档