Vue 3.0 中的效果
前言
本文源自自己研究总结,不教学,不科普。有兴趣的同学欢迎交流研究。 最先接触 Effect 的概念是在 React Hooks 中,可以在其中进行一些副作用操作。你只需要将准确的依赖传入,并且注册好你期望处理的副总用操作即可,React 中是这个样子使用的。
useEffect( () => {
document.title = a;
} [a])
当 a 变化时,对应的回调函数就会执行。
Vue3.0 Effect
Vue3.0
中的 effect 同样会在响应式数据发生改变时,去执行对象的注册回调。看下面的代码
const a = ref(1)
effect( () => {
console.log(a.value)
} )
a.value = 2 // 会打印2
虽然写法上有所区别,但是核心没有变,数据改变,执行我们期望中的事情(回调)。真要说区别其实也很明显,一个是显式的写入依赖,一个算半显式的(这取决于你心里有没有把数据当成显式的依赖)。
这里需要注意,effect
在注册完成后,如果没有传入相关参数(下面介绍那些参数),会立即执行一次回调函数用来依赖收集。
但是,今天只是做一个学习 3.0 effect
的记录,并不会展开对比,下面开始进入正题。
effect 的使用
effect
的最基本用发在上面例子中已经做了展示,这里会展示一个稍稍进阶点的用法 ---> 使用 effect
的返回值(本文中统一用 runner
来代替)
import { effect, reactive } from "@vue/reactivity"
let a = null;
let run = false;
const obj = reactive({props: 'value'})
const runner = effect(() => {
a = run ? obj.props : "other"
})
runner() // a === other
run = true
runner() // a=== value
runner
允许你在合适的时机手动去执行 effect
的回调,这一点给你使用者更多的发挥和想象空间。
注意: 如果传入的回调函数有返回值,将在执行 runner() 时返回对应的返回值。
Effect 的配置参数们
下面的表格展示了配置项和他们的介绍,后面会逐一给出例子方便理解和记忆。
api | 类型 | 参数 | 默认值 | 备注 |
---|---|---|---|---|
lazy | boolean | ~~~ | false | 此值为 true 时,只有在第一次手动调用 runner 后,依赖数据变更时,才会自动执行 effect 的回调,可以理解为 effect 的是在手动调用 runner 后才首次执行 |
scheduler | function | runner | none | 传入此参数,开启了调度模式,只有手动调用 runner 时,才会执行对应的注册回调 |
onTrack | function | trackType[](见下面 trackType) | none | 参数包含了依赖数据的每次更新进行的操作对象 |
onTrigger | function | trigger[](见下面 trigger) | none | 此方法是当依赖的数据被改变是会显示相应值得改变栈 |
onStop | function | none | none | 在调用 stop 停止 effect 时触发执行 |
interface trackType{
effect: runner, // effect 函数的返回值
target: toRaw(obj), // 表示的是发生属性变化的数据的源对象
type: TrackOpTypes.GET, // 表示此次记录操作的类型。 get 表示获取值(更多类型下面介绍)
key: 'foo' // 变化的键,可以是任意合法的键
}
interface tigger{
effect: runner,
target: toRaw(obj),
type: TriggerOpTypes.SET,
key: 'foo',
oldValue: 1,
newValue: 2
}
配置代码演示环节
lazy
import { effect, reactive } from "@vue/reactivity"
const obj = reactive({foo:1})
let a = null;
const runner = effect( () => (a = obj.foo) )
console.log(a) // null
runner() // 1 注意,如果回调函数有返回值,则 runner 函数的返回值与回调函数的返回值相同
obj.foo = 2
console.log(a) //2
scheduler
import { effect, reactive } from "@vue/reactivity"
let runner: any, dummy
const scheduler = _runner => {
runner = _runner
}
const obj = reactive({ foo: 1 })
const runner1 = effect(
() => {
dummy = obj.foo
},
{ scheduler }
)
console.log(dummy) // 1
// scheduler 将在这里首次被调用
obj.foo++
console.log(dummy) // 1 注意此时的值没有更新
runner() // 手动调用 runner , 在这里调用 runner1 也能达到同样的效果, 因为他们两个是同一个函数 使用 scheduler 方式可以使你的逻辑分离,使 runner 可以传播,已进行数据的更新
console.log(dummy) // 2 此时值更新了
onTrack
import { effect, reactive } from "@vue/reactivity"
let events = []
let dummy
const onTrack = (e) => {
events.push(e)
}
const obj = reactive({ foo: 1, bar: 2 })
const runner = effect(
() => {
dummy = obj.foo
dummy = 'bar' in obj
dummy = Object.keys(obj)
},
{ onTrack }
)
console.log('runner', runner)
console.log('dummy', dummy) // ['foo', 'bar']
obj.foo++
console.log("events", events)
// events 的格式如下
[
{
effect: runner, // effect 函数的返回值
target: toRaw(obj), // 表示的是哪个相应式数据发生了变化
type: TrackOpTypes.GET, // 表示此次记录操作的类型。 get 表示获取值
key: 'foo'
},
{
effect: runner,
target: toRaw(obj),
type: TrackOpTypes.HAS, // has 表示检测属性是否存在
key: 'bar'
},
{
effect: runner,
target: toRaw(obj),
type: TrackOpTypes.ITERATE, // 表示迭代
key: ITERATE_KEY
}
]
onTrigger
import { effect, reactive } from "@vue/reactivity"
let events = []
let dummy
const onTrigger = (e) => {
events.push(e)
}
const obj = reactive({ foo: 1 })
const runner = effect(
() => {
dummy = obj.foo
},
{ onTrigger }
)
obj.foo++ // 此时会调用 onTrigger
console.log(dummy) // 2
console.log(events[0])
/**
{
effect: runner,
target: toRaw(obj),
type: TriggerOpTypes.SET,
key: 'foo',
oldValue: 1,
newValue: 2
}
*/
delete obj.foo // 会执行 onTrigger
console.log(dummy) // undefined
console.log(events[1])
/**
{
effect: runner,
target: toRaw(obj),
type: TriggerOpTypes.DELETE,
key: 'foo',
oldValue: 2
}
*/
上一篇: 临江仙 - 又一个雨夜
下一篇: 2,4-dienoyl-CoA reductase regulates lipid homeostasis in treatment-resistant prostate cancer
推荐阅读
-
VUE] Vue 中的 keep-alive 组件Vue 中的 keep-alive 组件
-
通过 Vue 中的 v-bind 增强样式控制--(通过 v-bind 操作类和操作样式属性的详细说明,附示例和代码)
-
vue 中哈希模式和历史模式的区别 - IV 小结
-
vue3 中的计算属性
-
vue2 中的 vue-count-to 组件允许动态显示从某一数字到某一数字的数字(附带 vue3 的用法)。
-
java: pdfbox 3.0 从扫描的 PDF 文件中移除文本水印
-
学习 Webpack 中的图像 - JS-Vue-plugin
-
Vue3 中的 30 个高频重点面试问题
-
前端vue项目部署中,用户还在访问系统,存在缓存问题,部署后需要ctrlF5强制刷新,解决热更新的几种方案
-
vue 对象判断为空_Vue中可用的判断对象是否为空的方法