【React】从 setState 聊到 React 性能优化方法

setState的同步和异步

1.为什么使用setState

开发中我们并不能直接通过修改 state 的值来让界面发生更新

因为我们修改了 state 之后, 希望 React 根据最新的 Stete 来重新渲染界面, 但是这种方式的修改 React 并不知道数据发生了变化

React 并没有实现类似于 Vue2 中的 Object.defineProperty 或者 Vue3 中的Proxy的方式来监听数据的变化

我们必须通过 setState 来告知 React 数据已经发生了变化

疑惑: 在组件中并没有实现 steState 方法, 为什么可以调用呢?

原因很简单: setState方法是从 Component 中继承过来的

2.setState异步更新

setState是异步更新的

为什么setState设计为异步呢?

setState 设计为异步其实之前在 GitHub 上也有很多的讨论

React核心成员(Redux的作者)Dan Abramov也有对应的回复, 有兴趣的可以看一下

简单的总结: setState设计为异步, 可以显著的提高性能

如果每次调用 setState 都进行一次更新, 那么意味着 render 函数会被频繁的调用界面重新渲染, 这样的效率是很低的

最好的方法是获取到多个更新, 之后进行批量更新

如果同步更新了 state, 但还没有执行 render 函数, 那么state和props不能保持同步

state和props不能保持一致性, 会在开发中产生很多的问题

3.如何获取异步的结果

如何获取 setState 异步更新state后的值?

方式一: setState的回调

setState接收两个参数: 第二个参数是回调函数(callback), 这个回调函数会在state更新后执行

方式二: componentDidUpdate生命周期函数

3.setState一定是异步的吗?

其实可以分成两种情况

在组件生命周期或React合成事件中, setState是异步的

在setTimeou或原生DOM事件中, setState是同步的

验证一: 在setTimeout中的更新 —> 同步更新

验证二: 在原生DOM事件 —> 同步更新

4.源码分析

setState的合并

1.数据的合并

通过setState去修改message,是不会对其他 state 中的数据产生影响的

源码中其实是有对 原对象 和 新对象 进行合并的

2.多个state的合并

当我们的多次调用了 setState, 只会生效最后一次state

setState合并时进行累加: 给setState传递函数, 使用前一次state中的值

React 更新机制

1.React 更新机制

我们在前面已经学习React的渲染流程:

那么 React 的更新流程呢?

React基本流程

2.React 更新流程

React在 props 或 state 发生改变时,会调用 React 的 render 方法,会创建一颗不同的树

React需要基于这两颗不同的树之间的差别来判断如何有效的更新UI:

如果一棵树参考另外一棵树进行完全比较更新, 那么即使是最先进的算法, 该算法的复杂程度为 O(n 3 ^3 3),其中 n 是树中元素的数量

如果在 React 中使用了该算法, 那么展示 1000 个元素所需要执行的计算量将在十亿的量级范围

这个开销太过昂贵了, React的更新性能会变得非常低效

于是,React对这个算法进行了优化,将其优化成了O(n),如何优化的呢?

同层节点之间相互比较不会跨节点比较

不同类型的节点,产生不同的树结构

开发中,可以通过key来指定哪些节点在不同的渲染下保持稳定

情况一: 对比不同类型的元素

节点为不同的元素React会拆卸原有的树并且建立起新的树

当一个元素从  变成 ,从 

 变成 ,或从 

你可能感兴趣的:(【React】从 setState 聊到 React 性能优化方法)