共计 4079 个字符,预计需要花费 11 分钟才能阅读完成。
生命周期函数图谱
一、常用的生命周期函数
1.render()
render()
注意
(1) render()
方法是 class 组件中唯一 必须实现 的方法
(2) render()
函数应该为 纯函数
这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。如需与浏览器进行交互,请在 `componentDidMount()` 或其他生命周期方法中执行你的操作。保持 `render()` 为纯函数,可以使组件更容易思考。
(3) 如果 shouldComponentUpdate()
返回 false,则不会调用 render()
2.constructor()
在 React 组件挂载之前,会调用它的构造函数
constructor(props) {super(props);
// 不要在这里调用 this.setState()
this.state = {counter: 0};
this.handleClick = this.handleClick.bind(this);
}
如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。通常,在 React 中,构造函数仅用于以下两种情况:
- 通过给
this.state
赋值对象来初始化内部 state。 - 为事件处理函数绑定实例
注意:
(1) 在 constructor()
函数中 不要调用 setState()
方法 。如果你的组件需要使用内部 state,请直接在构造函数中为 this.state
赋值初始 state:
(2) 要避免在构造函数中引入任何副作用或订阅。如遇到此场景,请将对应的操作放置在 componentDidMount
中
(3) 避免将 props 的值复制给 state!这是一个常见的错误
constructor(props) {super(props);
// 不要这样做
this.state = {color: props.color};
}
3.componentDidMount()
componentDidMount()
会在组件挂载后(插入 DOM 树中)立即调用,依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,添加订阅等
componentDidMount()
注意:
(1) 你可以在 componentDidMount()
里 直接调用 setState()
它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 `render()` 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在 `constructor()` 中初始化 state。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理
4.componentDidUpdate()
componentDidUpdate()
会在更新后会被立即调用。首次渲染不会执行此方法。
componentDidUpdate(prevProps, prevState, snapshot)
componentDidUpdate(prevProps) {
// 典型用法(不要忘记比较 props):if (this.props.userID !== prevProps.userID) {this.fetchData(this.props.userID);
}
}
注意:
(1) 你也可以在 componentDidUpdate()
中 直接调用 setState()
,但请注意 它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。不要将 props“镜像”给 state,请考虑直接使用 props。
(2) 如果 shouldComponentUpdate()
返回值为 false,则不会调用 componentDidUpdate()
5.componentWillUnmount()
componentWillUnmount()
componentWillUnmount()
会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount()
中创建的订阅等。
注意:
(1) componentWillUnmount()
中 不应调用 setState()
,因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
二、不常用的生命周期函数
1.shouldComponentUpdate()
当 props 或 state 发生变化时,shouldComponentUpdate()
会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate()
时不会调用该方法。
shouldComponentUpdate(nextProps, nextState)
如果 shouldComponentUpdate()
返回 false
,则不会调用 UNSAFE_componentWillUpdate()
和 componentDidUpdate()
注意:
(1) 此方法仅作为性能优化的方式存在,不要试图通过此方法阻止重新渲染,可以使用内置的 PureComponent 组件,PureComponent 会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性
(2) 不建议在 shouldComponentUpdate()
中进行深层比较或使用 JSON.stringify()
。这样非常影响效率,且会损害性能
2.static getDerivedStateFromProps()
getDerivedStateFromProps
会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容
static getDerivedStateFromProps(props, state)
注意:
(1) 不管原因是什么,都会 在每次渲染前触发此方法。这与 UNSAFE_componentWillReceiveProps
形成对比,后者仅在父组件重新渲染时触发,而不是在内部调用 setState
时
3.getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate()
在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()
。
getSnapshotBeforeUpdate(prevProps, prevState)
三、16.13 版本过时的生命周期函数
1.UNSAFE_componentWillMount()
UNSAFE_componentWillMount()
在挂载之前被调用。它在 render()
之前调用,因此在此方法中同步调用 setState()
不会触发额外渲染。通常,我们建议使用 constructor()
来初始化 state。
UNSAFE_componentWillMount()
注意:
(1) 避免在此方法中引入任何副作用或订阅。如遇此种情况,请改用 componentDidMount()
(2) 此方法是服务端渲染唯一会调用的生命周期函数
2.UNSAFE_componentWillReceiveProps()
UNSAFE_componentWillReceiveProps()
会在已挂载的组件接收新的 props 之前被调用。如果你需要更新状态以响应 prop 更改(例如,重置它),你可以比较 this.props
和 nextProps
并在此方法中使用 this.setState()
执行 state 转换
UNSAFE_componentWillReceiveProps(nextProps)
注意:
(1) 如果父组件导致组件重新渲染,即使 props 没有更改,也会调用此方法。如果只想处理更改,请确保进行当前值与变更值的比较
3.UNSAFE_componentWillUpdate()
当组件收到新的 props 或 state 时,会在渲染之前调用 UNSAFE_componentWillUpdate()
。使用此作为在更新发生之前执行准备更新的机会。初始渲染不会调用此方法。
UNSAFE_componentWillUpdate(nextProps, nextState)
注意:
(1) 不能此方法中调用 this.setState()
(2) 此方法可以替换为 componentDidUpdate()
。如果你在此方法中读取 DOM 信息(例如,为了保存滚动位置),则可以将此逻辑移至 getSnapshotBeforeUpdate()
中
四、其他 API
1.setState()
setState(updater, [callback])
setState()
并不总是立即更新组件。它会批量推迟更新。这使得在调用 setState()
后立即读取 this.state
成为了隐患。为了消除隐患,请使用 componentDidUpdate
或者 setState
的回调函数(setState(updater, callback)
),这两种方式都可以保证在应用更新后触发。
this.setState((state, props) => {return {counter: state.counter + props.step};
});
2.forceUpdate()
component.forceUpdate(callback)
默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render()
方法依赖于其他数据,则可以调用 forceUpdate()
强制让组件重新渲染。
调用 forceUpdate()
将致使组件调用 render()
方法,此操作会跳过该组件的 shouldComponentUpdate()
。但其子组件会触发正常的生命周期方法,包括 shouldComponentUpdate()
方法。如果标记发生变化,React 仍将只更新 DOM。