Dawninest

React Native | 基础及生命周期(新)

React组件的生命周期(最新版)

Render()

1
在某一时间节点调用 React 的 render() 方法,会创建一棵由 React 元素组成的树。在下一次 state 或 props 更新时,相同的 render() 方法会返回一棵不同的树。React 需要基于这两棵树之间的差别来判断如何有效率的更新 UI 以保证当前 UI 与最新的树保持同步。

Diffing算法

1
2
3
4
当对比两颗树时,React 首先比较两棵树的根节点。不同类型的根节点元素会有不同的形态。当根节点为不同类型的元素时,React 会拆卸原有的树并且建立起新的树。当拆卸一棵树时,对应的 DOM 节点也会被销毁。组件实例将执行 componentWillUnmount() 方法。当建立一棵新的树时,对应的 DOM 节点会被创建以及插入到 DOM 中。组件实例将执行 componentWillMount() 方法,紧接着 componentDidMount() 方法。所有跟之前的树所关联的 state 也会被销毁。在根节点以下的组件也会被卸载,它们的状态会被销毁
当比对两个相同类型的 React 元素时,React 会保留 DOM 节点,仅比对及更新有改变的属性。当一个组件更新时,组件实例保持不变,这样 state 在跨越不同的渲染时保持一致。React 将更新该组件实例的 props 以跟最新的元素保持一致,并且调用该实例的 componentWillReceiveProps() 和 componentWillUpdate() 方法。下一步,调用 render() 方法,diff 算法将在之前的结果以及新的结果中进行递归。
在默认条件下,当递归 DOM 节点的子元素时,React 会同时遍历两个子元素的列表;当产生差异时,生成一个 mutation。在子元素列表末尾新增元素时,更变开销比较小
使用 key 来匹配原有树上的子元素以及最新树上的子元素 来解决头部插入比尾部插入开销大的问题,这个策略在元素不进行重新排序时比较合适,但一旦有顺序修改,diff 就会变得慢

组件的生命周期(新)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下
constructor()
static getDerivedStateFromProps()
会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
render()
componentDidMount()

componentWillMount() // 该方法即将过期,避免使用


当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给componentDidUpdate()
componentDidUpdate()

componentWillUpdate() // 该方法即将过期,避免使用
componentWillReceiveProps() // 该方法即将过期,避免使用

组件卸载
componentWillUnmount()

错误处理
static getDerivedStateFromError()
componentDidCatch()

forceUpdate()
默认情况下,当组件的 state 或 props 发生变化时,组件将重新渲染。如果 render() 方法依赖于其他数据,则可以调用 forceUpdate() 强制让组件重新渲染。
调用 forceUpdate() 将致使组件调用 render() 方法,此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发正常的生命周期方法,包括 shouldComponentUpdate() 方法。如果标记发生变化,React 仍将只更新 DOM。
通常你应该避免使用 forceUpdate(),尽量在 render() 中使用 this.props 和 this.state。