RN 组件的生命周期如下图:

?
生命周期回调函数
挂载
当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
注意:
下述生命周期方法即将过时,在新代码中应该避免使用它们:
UNSAFE_componentWillMount()
更新
当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
注意:
下述方法即将过时,在新代码中应该避免使用它们:
UNSAFE_componentWillUpdate()
UNSAFE_componentWillReceiveProps()
卸载
当组件从 DOM 中移除时会调用如下方法:
错误处理
当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:
static getDerivedStateFromError()
componentDidCatch()
?
常用的生命周期方法
1、render()
render() ?方法是 class 组件中唯一必须实现的方法。
当?render ?被调用时,它会检查?this.props ?和?this.state ?的变化并返回以下类型之一:
- React 元素。通常通过 JSX 创建。例如,
<div /> ?会被 React 渲染为 DOM 节点,<MyComponent /> ?会被 React 渲染为自定义组件,无论是?<div /> ?还是?<MyComponent /> ?均为 React 元素。
- 数组或 fragments。 使得 render 方法可以返回多个元素。。
- Portals。可以渲染子节点到不同的 DOM 子树中。
- 字符串或数值类型。它们在 DOM 中会被渲染为文本节点
- 布尔类型或?
null 。什么都不渲染。(主要用于支持返回?test && <Child /> ?的模式,其中 test 为布尔类型。)
render() ?函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。
如需与浏览器进行交互,请在?componentDidMount() ?或其他生命周期方法中执行你的操作。保持?render() ?为纯函数,可以使组件更容易思考。
注意
如果?shouldComponentUpdate() ?返回 false,则不会调用?render() 。
2、constructor()
如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。
在 React 组件挂载之前,会调用它的构造函数。在为 React.Component 子类实现构造函数时,应在其他语句之前前调用?super(props) 。否则,this.props ?在构造函数中可能会出现未定义的 bug。
通常,在 React 中,构造函数仅用于以下两种情况:
- 通过给?
this.state ?赋值对象来初始化内部 state。
- 为事件处理函数绑定实例
在?constructor() ?函数中不要调用?setState() ?方法。如果你的组件需要使用内部 state,请直接在构造函数中为?this.state ?赋值初始 state。
要避免在构造函数中引入任何副作用或订阅。如遇到此场景,请将对应的操作放置在?componentDidMount ?中
?
3、componentDidMount()
componentDidMount() ?会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。
这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在?componentWillUnmount() ?里取消订阅
你可以在?componentDidMount() ?里直接调用?setState() 。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在?render() ?两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在?constructor() ?中初始化 state。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理
?
4、componentDidUpdate()
componentDidUpdate() ?会在更新后会被立即调用。首次渲染不会执行此方法。
当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。
componentDidUpdate(prevProps) {
// 典型用法(不要忘记比较 props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
?
你也可以在?componentDidUpdate() ?中直接调用?setState() ,但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。不要将 props “镜像”给 state,请考虑直接使用 props。
?
5、componentWillUnmount()
componentWillUnmount() ?会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在?componentDidMount() ?中创建的订阅等。
componentWillUnmount() ?中不应调用?setState() ,因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
?
不常用的生命周期方法
并不太常用。它们偶尔会很方便,但是大部分情况下组件可能都不需要它们。
?
1、shouldComponentUpdate()
根据?shouldComponentUpdate() ?的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。
?
2、static getDerivedStateFromProps()
getDerivedStateFromProps ?会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
此方法适用于?state 的值在任何时候都取决于 props。
派生状态会导致代码冗余,并使组件难以维护。?确保你已熟悉这些简单的替代方案:
- 如果你需要执行副作用(例如,数据提取或动画)以响应 props 中的更改,请改用?
componentDidUpdate 。
- 如果只想在?prop 更改时重新计算某些数据,请使用 memoization helper 代替。
- 如果你想在 prop 更改时“重置”某些 state,请考虑使组件完全受控或使用?
key ?使组件完全不受控?代替。
3、getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate() ?在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给?componentDidUpdate() 。
此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。
应返回 snapshot 的值(或?null )。
?
Error boundaries
Error boundaries?是 React 组件,它会在其子组件树中的任何位置捕获 JavaScript 错误,并记录这些错误,展示降级 UI 而不是崩溃的组件树。Error boundaries 组件会捕获在渲染期间,在生命周期方法以及其整个树的构造函数中发生的错误。
如果 class 组件定义了生命周期方法?static getDerivedStateFromError() ?或?componentDidCatch() ?中的任何一个(或两者),它就成为了 Error boundaries。通过生命周期更新 state 可让组件捕获树中未处理的 JavaScript 错误并展示降级 UI。
仅使用 Error boundaries 组件来从意外异常中恢复的情况;不要将它们用于流程控制。
欲了解更多详细信息,请参阅?React 16 中的错误处理。
注意
Error boundaries 仅捕获组件树中以下组件中的错误。但它本身的错误无法捕获。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|