zustand 增加计算属性
🗒️zustand 增加计算属性
react|2023-7-3|最后更新: 2023-7-3
type
status
date
slug
summary
tags
category
icon
password
Blocking
Blocked by
top
URL
Sub-item
Parent item

背景

  1. 由于页面复杂度很高,我们目前大量使用状态管理来控制页面,每次重新渲染的代价都很高。因此,为了最大程度地优化性能,需要确保只有在必要的情况下才会重新渲染组件。
  1. 目前我们使用了zustand作为状态管理工具,在未进行性能优化时默认使用,会导致任意state发生变化时,都会触发组件的重新渲染。

基本思想

  1. 组件只订阅需要的state,实现只有订阅的属性变化,才会重新渲染。
  1. 优化衍生属性的计算,通过缓存衍生属性,每次只有依赖的属性变化时才会重新计算。

详细设计

封装useStore

  1. 强制指定订阅的属性。
  1. 基于zustand/shallow提供的浅相等函数来进行浅层差异比较。

缓存衍生属性

封装一个zustand的中间件,第一个参数传入属性,第二个参数传入一个计算属性函数组成的对象。
原理类似于vue的计算属性(主要思想是利用观察者模式和 Proxy,通过定义可观察对象和订阅者来监听状态变化并进行计算,从而避免不必要的计算或渲染,当计算属性所依赖的state发生变化时,计算属性会自动重新计算其值)。
可以做更细致优化,待以后需要时再做改造:
  1. 计算属性的互相依赖。
  1. 懒加载:目前是初始化就会计算一次,可以改造成在第一次访问时计算。
中间件实现:
  1. 初始化时进行建立映射表,收集状态被哪些计算属性依赖,并进行第一次计算。
  1. set后,通过比较,遍历出哪些被依赖的状态发生变化,对应计算属性重新计算。
 
存在问题:计算属性不能依赖其他的计算属性。
后来发现zustand的作者还写了一个proxy-memoize的库,原理是通过proxy收集用到的参数,如果没有变化就会返回上一次的返回值。于是优化中间件:
 
最后封装成一个npm包:
zustand-middleware-computed
lxw15337674Updated Sep 12, 2023
 

对比效果

减少rerender

优化前:每次state修改都会触发重新渲染。
优化后:只有订阅的state发生变化才会触发重新渲染。
优化前:
notion image
优化后:
notion image
 

缓存衍生属性

优化前:每个引用属性的组件都会重新计算一次。
优化后:衍生属性只会计算一次。
 
优化前:
notion image
优化后:
notion image
 
参考:
styled-compoents 传参使用博客迁移记录
Loading...