shallowRef/triggerRef
shallowRef: 浅层的
ref
triggerRef: 强制让一个 浅层的
ref
触发effect
什么是浅层的 ref
html
<template>
<div>
<p>{{ simpleRef.count }}</p>
<button @click="increment">shallowRef value increment</button>
<button @click="setIncrement">shallowRef reset value</button>
</div>
</template>
<script setup>
import { shallowRef, effect } from 'vue';
const simpleRef = shallowRef({ count: 0 });
effect(() => {
console.log('simpleRef.value.count:', simpleRef.value.count);
});
function increment() {
// 改变 ref 的 value 的值不会触发 effect
// 如果是 用 ref() 函数定义的值, 改变 value 会触发 effect
simpleRef.value.count++;
}
function setIncrement() {
// 重新给 ref 的 value 赋值会触发 effect
simpleRef.value = {
count: Math.random(),
};
}
</script>
什么叫强制触发依赖于一个浅层 ref 的副作用(effect)
html
<template>
<div>
<p>{{ simpleRef.count }}</p>
<button @click="increment">shallowRef value increment</button>
<button @click="setIncrement">shallowRef reset value</button>
</div>
</template>
<script setup>
import { shallowRef, effect, triggerRef } from 'vue';
const simpleRef = shallowRef({ count: 0 });
effect(() => {
console.log('simpleRef.value.count:', simpleRef.value.count);
});
function increment() {
// 默认不会触发
simpleRef.value.count++;
// 强制触发这个 shallowRef 的所有依赖(effect)
triggerRef(simpleRef);
}
function setIncrement() {
// 会触发 effect
simpleRef.value = {
count: Math.random(),
};
}
</script>
customRef
- customRef: 自定义 ref 收集依赖和触发依赖
html
<template>
<div>{{ evenRef }}</div>
<button @click="increment(1)">increment 1</button>
<button @click="increment(2)">increment 2</button>
</template>
<script setup>
import { customRef, effect } from 'vue';
function useEvenRef(value, delay = 2000) {
return customRef((track, trigger) => {
return {
get() {
// 自定义如何收集依赖
console.log('getter', value);
track();
return value;
},
set(newValue) {
// 自定义如何触发依赖
value = newValue;
console.log('setter', value);
if (typeof value === 'number' && value % 2 === 0) {
trigger();
}
},
};
});
}
const evenRef = useEvenRef(0);
effect(() => {
console.log('---effect---', evenRef.value);
});
function increment(step) {
evenRef.value += step;
}
</script>
effectScope
- effectScope 创建一个 effectScope 容器
- getCurrentScope 获取当前 effectScope 容器上下文容器对象
- onScopeDispose 当当前的 effectScope 容器上下文调用
stop
方法的时候执行
什么是 effectScope
html
<template>
<div>{{ state.count }}</div>
<button @click="incrementCount">increment</button>
<button @click="scopeStop">stopScope</button>
</template>
<script setup>
import { effectScope, reactive, effect, watchEffect, getCurrentScope } from 'vue';
const effectScope1 = effectScope();
const state = reactive({
count: 0,
});
// 1.1 获取外界的顶层的 scope 上下文对象
const topScope = getCurrentScope();
topScope.__mark = 'topScope';
console.log('setup topScope:', topScope);
effect(() => {
console.info('[outside-effect]', state.count);
});
// setup 顶层的 effectScope 作用域不用手动调用 run, effect 会生效
// 但是用 effectScope() 执行生成的作用域必须手动调用 run, 才能让其中的 effect 生效
effectScope1.run(() => {
// 1.2 获取 effectScope1 里面的 scope 上下文对象
const effectScope1 = getCurrentScope();
effectScope1.__mark = 'effectScope1';
console.log('effectScope1:', effectScope1);
// 在作用域内部创建响应式数据和副作用函数
effect(() => {
console.log('[scope-run-effect]:', state.count);
});
watchEffect(() => {
console.log('[scope-run-watchEffect]:', state.count);
});
});
// 2.1. 当 scope.run 执行之后, 如果响应式数据发生改变
// 会执行这个作用域中的 effect 和 watchEffect
function incrementCount() {
state.count++;
}
// 2.2. 当 scope.stop 执行之后, 如果响应式数据发生改变
// 就不会再执行这个作用域中的 effect 和 watchEffect
// 但是外界的 outside-effect 不受影响
function scopeStop() {
effectScope1.stop();
// outsideScope.stop(); // 如果把外界最顶层的 scope 调用 stop 就会让所有的 effect 失效
}
</script>