前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一种基于依赖收集的最小化更新组件技术

一种基于依赖收集的最小化更新组件技术

作者头像
否子戈
发布2021-06-10 10:16:14
6140
发布2021-06-10 10:16:14
举报
文章被收录于专栏:

最近被react的性能问题折腾惨了,在实际项目开发中,组件的深度可能很深很深,而react的更新机制本质上还是一种全量的脏检查,也就是从当前组件开始,把它作为根节点的整棵树都检查一遍,并且在这过程中做diff,中间涉及一些算法,这些算法说来说去还是因为它存在性能问题,需要靠复杂的算法来迎合react这种脏检查带来的坏处。那么,有没有一种办法,可以避免这种脏检查,也就是在整棵树中,我只需要更新其中一个节点即可。Mobx提供了一种创新的方法,就是对组件所需要的数据进行收集,只有当这个数据发生变化的时候,这个组件才需要重新渲染。这里面还涉及到整个项目中所有组件本身的设计问题。本文尝试基于mobx的这种思路,提出一种基于依赖收集的最小化更新组件技术。

React组件性能优化的途径

单纯从优化的途径出发,React组件有以下几种途径可以让开发者进行性能优化:

  • PureComponent
  • shouldComponentUpdate
  • React.memo

其中PureComponent实际上内置了shouldComponentUpdate的特殊逻辑。React.memo针对functional组件,本质上还是差不多,通过对比props来决定是否要更新当前组件。但是注意,shouldComponentUpdate可以控制this.state的变化引起更新,而React.memo无法控制useState带来的更新。

但在实际开发中,我们往往很难简单通过这些手段进行优化,因为state和props具有非常复杂的关系,我们往往找不到准确的控制是否更新的逻辑。

响应式本质

无论是vue还是react,都是响应式视图框架,通过修改数据来达到改变界面的效果。响应式是现代前端框架的基本要求。对于开发者而言,应该透过响应式的表象,看到它的本质——观察者模式/订阅发布模式。vue通过对数据劫持,在发生数据变化时,执行劫持代码中的触发逻辑,触发更新机制。react则是在setState等接口被调用时,触发更新机制。它们本质上都是通过一个方式触发更新。

基于这一理解,我们再看redux,它是一个状态管理器,在和react结合使用时,本质上,它也是订阅发布器。只是库的作者封装了store.subscribe/store.dispatch方法,让很多开发者只看到状态的变化,没有看到订阅发布的过程。这实际上启发我们理解一个核心问题:单向双向数据流也好,immutable或mutable也好,不是react或vue界面更新机制的必要条件,必要条件是触发过程,也就是说,无论是哪种数据流或哪种数据形态,只要数据变化之后,能够触发框架的更新机制,就可以完成更新。

这有什么用呢?

我们不需要redux或vuex,我们可以用mobx了。Mobx和前两者都有巨大的不同,你可以把它当作一个状态管理器,但是,本质上,它不是专门为前端框架们特制的一个状态管理器,它是一个通用的数据模型生成器。当你需要对一个物品/对象进行描述时,可以用Mobx对该物品/对象进行描述,有什么属性,什么方法,都可以定义在Mobx的模型上。而mobx提供了多个方法,可以帮助开发者对这些属性和方法,做更加深入和魔幻的控制,比如让一个属性的值依赖另外一个属性的值,被依赖属性的值发生变化时,该属性的值也自动变化。所以,抛开前端框架来讲,它只是一个用于创建数据的模型生成器。另外,你可以通过它的接口,订阅模型实例上属性的变化,至于界面的更新,则是把框架的更新机制的触发接口丢到这个订阅函数中去。如果你需要一个理解起来更简单的数据模型,可以尝试我写的模式库tyshemo(npm i tyshemo)来做这个响应式的模型对象。

因此,我们在react之外建立的响应式数据体系,可以很轻松的按照观察者模式/订阅发布模式接入到react中。比较简单粗暴的一种方式:

代码语言:javascript
复制
// 假如 model 是一个可订阅的对象
function ReactComponent(props) {
  const [, setState] = useState({})

  useEffect(() => {
    const forceUpdate = () => setState({})
    model.subscribe(forceUpdate)
    return () => model.unsubscribe(forceUpdate)
  }, [])

  // ....
}

这是最最最简单的实现了,可以看到,我们已经可以用一个react之外的可订阅对象完成react的响应式更新,也就是说,当我们在该组件外更新了model,那么该组件就会被更新。如果我们在多个组件中都做了这个操作,那么这些组件都会随着model上属性的变化而进行更新。

依赖收集

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 唐霜 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • React组件性能优化的途径
  • 响应式本质
  • 依赖收集
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档