响应式
深入响应式信号
在本教程中,我们将学习如何使用上面的代码构建一个简单的响应式系统。我们将介绍 signal, computed 和 effect 的概念以及如何使用它们来构建响应式应用程序。
了解 signal
signal 是一个包装了值的对象,signal 是一个具有 .value 属性的对象,该属性保存了一个值通过 .value
访问。这有一个重要的特性:信号的值可以改变,但信号本身始终保持不变。它允许你观察和修改这个值。当值发生变化时,它会通知所有依赖于这个值的函数。我们可以使用 signal
函数来创建一个 signal 对象。
const counter = signal(0);
const counter = signal(0);
上面的代码创建了一个 signal 对象,其初始值为 0。我们可以使用 value
属性来访问和修改 signal 的值。
console.log(counter.value); // 输出 0
console.log(counter.value); // 输出 0
使用 computed 创建计算属性
computed 是一个根据其他 signal 值计算出的 Signal。当依赖的 signal 值发生变化时,computed signal 的值将自动更新。
我们可以使用 computed
函数来创建一个 computed Signal。
const counter = signal(0);
const doubledCounter = computed(() => counter.value * 2);
console.log(doubledCounter.value); // 输出 0
counter.value = 1;
console.log(doubledCounter.value); // 输出 2
const counter = signal(0);
const doubledCounter = computed(() => counter.value * 2);
console.log(doubledCounter.value); // 输出 0
counter.value = 1;
console.log(doubledCounter.value); // 输出 2
上面的代码创建了一个名为 doubledCounter 的 computed Signal,它的值始终是 counter 值的两倍。
使用 peek 偷看 signal 值
const name = signal('Dnt')
const surname = signal('Zhang')
const fullName = computed(() => name.peek() + ' ' + surname.value)
let effectTimes = 0
effect(() => {
// 访问 fullName.value 会触发依赖
fullName.value
effectTimes++
})
name.value = 'John'
// 因为 peek 不会触发依赖,所以 effectTimes 仍然是 1
expect(effectTimes).toBe(1)
const name = signal('Dnt')
const surname = signal('Zhang')
const fullName = computed(() => name.peek() + ' ' + surname.value)
let effectTimes = 0
effect(() => {
// 访问 fullName.value 会触发依赖
fullName.value
effectTimes++
})
name.value = 'John'
// 因为 peek 不会触发依赖,所以 effectTimes 仍然是 1
expect(effectTimes).toBe(1)
使用 effect 跟踪依赖关系
effect 是一个允许我们在函数中跟踪 signal 值变化的功能。当我们在 effect 函数中访问一个 signal 的值时,该函数将自动跟踪这个值的变化。当 signal 值发生变化时,Effect 函数将重新运行。
我们可以使用 effect
函数来创建一个 Effect。
const counter = signal(0)
const dispose = effect(() => {
console.log(`Counter: ${counter.value}`)
})
// 停止跟踪依赖关系
dispose()
const counter = signal(0)
const dispose = effect(() => {
console.log(`Counter: ${counter.value}`)
})
// 停止跟踪依赖关系
dispose()
上面的代码将在 counter 值发生变化时输出新的值。例如,当我们将 counter 值更改为 1 时,Effect 函数将输出 "Counter: 1"。
使用 update 触发 effect
const testSignal = signal([1,2,3])
let effectTimes = 0
effect(() => {
console.log(testSignal.value)
effectTimes++
})
testSignal.value.push(4)
// 和 testSignal.value = testSignal.value 一样会触发 effect
testSignal.update()
expect(effectTimes).toBe(2)
const testSignal = signal([1,2,3])
let effectTimes = 0
effect(() => {
console.log(testSignal.value)
effectTimes++
})
testSignal.value.push(4)
// 和 testSignal.value = testSignal.value 一样会触发 effect
testSignal.update()
expect(effectTimes).toBe(2)
总结
在本教程中,我们学习了如何使用 signal, computed 和 effect 构建响应式系统。我们了解了如何创建 signal 对象,如何使用 effect 函数跟踪依赖关系,如何使用 computed 创建计算属性,以及如何使用 batch 进行批处理更新。
现在,您已经了解了如何使用这些基本概念来构建响应式应用程序。尝试使用这些知识创建您自己的响应式系统,并不断学习和实践以提高您的技能。