简介
最近听到很多小伙伴面试题上都会碰到一道比较经典的React批量更新
(状态合并)的题目,每个人都有各的答法,但其实很少有人能够非常好的给出这一题目的答案,如果你刚好在准备明年跑路
,那么这一题看了可能会给你无形中给与一个帮助。
那么,请看题目
- 在
class
组件中,以下代码同时执行究竟会渲染几次视图,请结合场景作答?
// state默认所有值初始化都为0
this.setState({ a: 1 })
this.setState({ b: 1})
this.setState({ c: 1 })
上述题中,主要问的知识点就是React
的渲染更新问题,分别是有状态组件和无状态组件在更新state
行为的一个作用变化结果的思考。如果你平时善于实践,那么这种题目实际上算是送分题,通过不难,但是回答的满意就很让人头疼了,这个题目能够向下深挖出对React
机制的一些理解。
什么是批量更新?
在React Class Component
中,setState
会触发DOM的一个render
,其实也变相的是激发Virtual-Dom
的一个更新行为,那么批量更新
的操作模式就诞生了。
我们在消费一件商品的时候,扫码支付并不会故意存在分多个批次给商家转账的情况,而是一次性转入到账。所以,在一笔消费的方法中,所有setState
其实本身只需要进行付账一次,就好比去超市购物,购物车里面有非常的东西,但是我们最终都是统一结账掉的,并不是买一件,付一件。
因此,setState
,看起来是下面这个样子的,在同一批次的setState
的值,都会被添加到合并队列中去,进行一个state
合并的过程。
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
callback?: () => void
): void;
forceUpdate(callback?: () => void): void;
举个例子:如下,就是一个未合并之前的一个函数行为,分别分三次设置了不同的state
的值。如果不加以处理,那么将会渲染三次render
函数的触发。
合并前 =>
this.setState({a: 1})
this.setState({b: 1})
this.setState({c: 1})
可以看到三次行为都被拉入一批队列中,进行了值合并。
合并后 =>
this.setState({
a: 1,
b: 1,
c: 1,
})
异步触发更新时
虽然React
为我们做了更新的合并,但是这往往都是取决于React
能够鉴定你触发更新行为的时候。但是,当我们的setState
在异步中的时候,React
并不知道我们还有更新需要执行,因此,他以为你这个函数不需要合并更新,那么它就不会给你进行一个state 合并
的操作了。可以看下面这张运行图:
在执行Promise
结果中处理的setState
并没有合并,依旧被执行了三次,意味着render
视图被执行了三次更新,这个无疑是非常浪费,对性能来说产生了无意义的开销。
那么到了这里,大家获取就明白了很多了,如果我们使用了React
本身无法监听调度的API
的话,setState
的事件合并就需要开发者来做调度了。
调度更新
在React
中,暴露出两个可以自主触发视图更新的API
能够给开发者手动更新。
forceUpdate
forceUpdate
就非常好理解了,调用这个函数的时候会直接强制刷新。传入的函数则是刷新后的一个回调事件。从下面类型推导来看的话,它的作用并不理想(不推荐使用),对正常开发情况下来说,如果需要涉及强制更新的话,往往是代码存在一些问题,大多数情况下都不需要使用到。
forceUpdate(callback?: () => void): void;
unstable_batchedUpdates
unstable_batchedUpdates
则是手动合并处理事件了,之前的更新调度是React
帮我们做的,而现在的话相当于我们自己去声明自己的调度,来主动合并事件。
但是,细心的小伙伴可能发现了, unstable_batchedUpdates
带了unstable
来表明是不稳定的,虽然说使用上来讲是没有问题,但还是不推荐进行使用。
handelClick = () => {
mockData().then(() => {
margeUpdate(() => {
this.setState({a: 1})
this.setState({b: 1})
this.setState({c: 1})
})
})
}
开发时合并
更加理想的情况下是主动在开发时,能够合并的State
尽量合并成为一个对象,而不是拆成零散的属性,这样对React
的一些分担压力还是蛮大的。
// 未合并
state = {
a: 1,
b: 2,
c: 3
}
// 合并
state = {
obj: {
a: 1,
b: 2,
c: 3
}
}
看看Hooks
其实函数组件
也有相似的问题,而且更加的直观,因为函数组件
本身没有状态,所有的状态行为都来自于副作用,当副作用频繁触发的时候,useEffect
相关满足依赖的行为可能会被频繁的触发。
总结
不论是在函数组件
还是Class组件
,在开发的时候都需要合理根据业务定制好state
的数据结构,这样的话在后续做数据更新时,才可能尽量少的情况下做视图更新,节省性能。
承上启下,那么开头的问题,你知道怎么回事了吗。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!