Vue3中computed实现原理

news/2024/10/22 14:32:45/

什么是computed?

他是组件的计算属性,依赖其他状态的变化而生成的状态。

如何使用computed

源码说明:要么传递一个函数作为getter,要么传递一个包含get和set 的对象

<script setup>
import { ref,computed} from 'vue'const count = ref(1);
const comCount = computed(()=>count.value+'computed')
</script><template><h1>{{ count }}</h1><div>{{comCount}}</div>
</template>
<script setup>
import { ref,computed} from 'vue'const count = ref('1');
const comCount = computed({get:()=>count.value+'--get',set:(val)=>count.value=val+'--set'
})
// 输出:1 1--get
comCount.value='2';
// 输出:2--set 2--set--get
</script><template><h1>{{ count }}</h1><div>{{comCount}}</div>
</template>

computed缓存值的原理

大家请先看reactive响应式相关代码,要不在看这边文章时,有点蒙。 

我们都知道,computed会缓存数据,只有依赖数据发生变化时才会重新计算,否则读取以前的值。 

分析源码:

// ComputedGetter就是一个函数类型
export function computed<T>(getter: ComputedGetter<T>,debugOptions?: DebuggerOptions
): ComputedRef<T>// WritableComputedOptions内部定义get和set类型
export function computed<T>(options: WritableComputedOptions<T>,debugOptions?: DebuggerOptions
): WritableComputedRef<T>// 主要逻辑实现
export function computed<T>(getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,debugOptions?: DebuggerOptions,isSSR = false
) {let getter: ComputedGetter<T>let setter: ComputedSetter<T>const onlyGetter = isFunction(getterOrOptions)// 如果是函数直接赋值getter,否则将对象内的get和set方法分别赋值getter和setterif (onlyGetter) {getter = getterOrOptionssetter = __DEV__? () => {console.warn('Write operation failed: computed value is readonly')}: NOOP} else {getter = getterOrOptions.getsetter = getterOrOptions.set}const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)if (__DEV__ && debugOptions && !isSSR) {cRef.effect.onTrack = debugOptions.onTrackcRef.effect.onTrigger = debugOptions.onTrigger}return cRef as any
}

上述代码只是定义getter和setter,并进行赋值函数。然后创建ComputedRefImpl实例,并返回此实例。那么我们可以知道缓存功能就在这个函数中。

export class ComputedRefImpl<T> {public dep?: Dep = undefinedprivate _value!: Tpublic readonly effect: ReactiveEffect<T>public readonly __v_isRef = truepublic readonly [ReactiveFlags.IS_READONLY]: boolean = falsepublic _dirty = truepublic _cacheable: booleanconstructor(getter: ComputedGetter<T>,private readonly _setter: ComputedSetter<T>,isReadonly: boolean,isSSR: boolean) {this.effect = new ReactiveEffect(getter, () => {if (!this._dirty) {this._dirty = truetriggerRefValue(this)}})this.effect.computed = thisthis.effect.active = this._cacheable = !isSSRthis[ReactiveFlags.IS_READONLY] = isReadonly}get value() {// the computed ref may get wrapped by other proxies e.g. readonly() #3376const self = toRaw(this)trackRefValue(self)if (self._dirty || !self._cacheable) {self._dirty = falseself._value = self.effect.run()!}return self._value}set value(newValue: T) {this._setter(newValue)}
}

 上述代码:调用此构造函数时,会创建ReactiveEffect构造函数(创建响应式副作用函数),并将实例赋值effect。将ComputedRefImpl实例赋值副作用函数实例的computed函数,在依赖更新时的判断条件。赋值副作用函数为活跃状态active。内部定义了get和set 方法,当使用实例调用或赋值时会触发get和set。  初始化不会执行getter,当调用时才会触发,这是因为调用时执行了ReactiveEffect实例的run方法,才会执行getter方法,并将返回值赋值_value。

ReactiveEffect 在讲响应式中有讲到过,大家可以查看。

这里在读取computed时,也会进行依赖收集(上边所说的effect)。初始化_dirty=true,满足条件讲_dirty赋值false,所以在此读取computed不会重新计算,然后执行run方法得到getter函数返回值赋值_value,并返回_value。

依赖更新时如何监听到的呢? 上述说了读取时会进行依赖收集,在创建ReactiveEffect实例时,存储了scheduler,再进行依赖更新(trigger())会判断是否有scheduler,有则执行函数。就会再次进行依赖更新就会重新触发getter函数,并将_dirty赋值true。这样在依赖变更时,读取computed值就会变化。


http://www.ppmy.cn/news/705905.html

相关文章

飞控学习笔记-姿态角的描述(1)

方向余弦矩阵 c12为方向余弦矩阵 四元数 欧拉角 四元数-方向余弦-欧拉角的关系

i3wm学习笔记-基础快捷键

i3wm 基础快捷键 多屏显示 xrandr --output HDMI2 --auto --right-of HDMI-3 mod ctrl: $mod config alt :Mod1 Win键:Mod4打开一个虚拟终端 modenter …

Fedora-i3折腾笔记

Fedora-i3折腾笔记 介绍安装 * 下载fedora-i3 * 制作安装盘 * 开始安装配置 * 添加软件源 * 高分辨率屏幕 * 触摸板 * neovim * 常用软件 * 输入法 * ohmyzsh&#xff08;终端美化&#xff09; * v2rayA * refind我的配置文件的使用 介绍 这里推荐下我个人的GitHub主页&#xf…

archlinux安装i3桌面

说明 首先安装xorg或xorg-server&#xff0c;再安装i3 xorg-server是x window的实现&#xff0c;是用于显示图形界面。 安装依赖zsh、xfce4-terminal、feh、compton zsh是个人推荐使用的shell&#xff0c;如果你想用默认的shell&#xff0c;这个可以不装 terminal这里用的是xf…

ubuntu+i3wm桌面

某天突然看到i3wm&#xff0c;简洁的桌面让我心头激动。 平铺式、全键盘、这感觉应该要飞起来。 一、换源 emacs /etc/apt/sources.list 中国源 sudo apt update 二、卸载unity桌面&#xff1a; sudo apt-get remove ubuntu-desktopsudo apt-get remove unitysudo apt-g…

Ubuntu20.04+i3wm折腾笔记

最近出差,没事折腾了一下笔记本直接装成了Ubuntu 20.04,顺带研究了下Rime输入法和i3桌面环境,记录一下填坑的过程 触摸板tap-to-click 真不知道该咋翻译这个tap-to-click,反正就是在默认的Gnome环境下,使用触摸板可以点一下模拟鼠标的左键单击,但是在i3里面只能实现移动/双指滚…

i3wm i3status状态栏实时显示网速

重要的话&#xff1a;修改配置之前最好先备份一下配置文件&#xff0c;防止改错了&#xff0c;而你又找不到问题&#xff01; 项目地址&#xff1a;https://github.com/i3/i3status/blob/master/contrib/net-speed.sh 下载&#xff1a; sudo apt install subversion svn chec…

Arch + i3wm + i3lock-wrapper 毛玻璃锁屏

今儿个 又看i3lock-wrapper的时候看了下man xautolock&#xff0c;发现了一些有意思的选项。 毛玻璃锁屏是酱紫的&#xff1a; 在.xinitrc里&#xff08;startx的时候会执行.xinitrc里的命令&#xff09;使i3lockwrapper.sh于后台运行&#xff0c;这个sh里再调用xautolock设置…