细粒度响应式
编辑此页面响应式确保自动响应数据更改,而无需手动更新用户界面 (UI)。通过将 UI 元素连接到底层数据,更新变得自动化。在细粒度响应式系统中,应用程序能够进行高度有针对性的和具体的更新。
Solid 和 React 之间的对比就是一个例子。在 Solid 中,只对需要更改的目标属性进行更新,从而避免更广泛且有时不必要的更新。相比之下,React 会针对单个属性的更改重新执行整个组件,这可能会降低效率。
由于细粒度响应式系统,不必要的重新计算将被避免。通过仅针对发生更改的应用程序区域,用户体验将变得更加流畅。
注意:如果您对响应式概念不熟悉并且想要学习基础知识,请考虑从我们的响应式介绍指南开始。
响应式原语
在 Solid 的响应式系统中,有两个关键元素:信号(signals)和观察者(observers)。这些核心元素是更专业的响应式功能的基础:
- Stores 本质是代理,用于在底层创建、读取和写入信号。
- Memos 类似于 effects,但不同之处在于它返回 signals 并通过缓存优化计算。它们基于 effect 行为进行更新,但更适合计算优化。
- Resources 建立在 memos 概念之上,将网络请求的异步性转换为同步性,将结果嵌入到 signal 中。
- Render effects 是一种立即启动的定制 effect 类型,专为管理渲染过程而设计。
了解信号
Signals 就像可变变量,可以指向现在的值和将来的另一个值。它们由两个主要功能组成:
Getter
:如何读取信号的当前值。Setter
:一种修改或更新信号值的方法。
在 Solid 中,createSignal 函数可用于创建信号。此函数将 getter 和 setter 作为数组中的元素返回:
在这个例子中,count
是 getter,setCount
就是 setter。
Effects
Effects 是当它们所依赖的 signals 指向不同值时触发的函数。它们可以被认为是自动响应器,signals 值的任何变化都会触发 effect 运行。
在这个例子中,effect 依赖 count
,只要 count
发生改变,就会调用该函数。
构建响应式系统
要掌握响应式的概念,从头开始构建响应式系统通常会有所帮助。
以下示例遵循观察者模式,其中数据实体(signals)将维护其订阅者(effects)列表。这是一种在订阅者观察到的 signal 发生变化时通知订阅者的方法。
以下是代码大纲:
响应式原语
createSignal
createSignal
函数执行两个主要任务:
- 初始化该值(在本例中,
count
设置为0
)。 - 返回一个包含两个元素的数组:getter 和 setter 函数。
这允许您通过 getter 检索当前值并通过 setter 进行任何更改。然而,在此阶段,还不存在响应式。
createEffect
createEffect
定义一个函数,该函数立即调用传递给它的函数:
使系统具有响应式
当链接 createSignal
和 createEffect
时会出现响应式,这是通过以下方式发生的:
- 维护对当前订阅者函数的引用
- 在创建 effect 期间注册此函数。
- 访问 signal 时将该函数添加到订阅者列表中。
- signal 更新时通知所有订阅者。
一个变量(currentSubscriber
)用于保存对当前正在执行的订阅者函数的引用。这用于确定哪些 effects 取决于哪些 signals。
在 createSignal
内部,初始值被存储,并且使用 Set 来存储依赖于 signal 的任何订阅者函数。然后,该函数将返回该 signal 的两个函数:
getter
函数检查当前订阅者函数是否正在被访问,如果是,则在返回信号的当前值之前将其添加到订阅者列表中。setter
函数根据旧值评估新值,仅在 signal 更新时通知相关函数。
创建 createEffect
函数时,将初始化对任何先前订阅者的引用,以处理可能的嵌套效果。然后,当前订阅者被传递给给定的函数,该函数会立即运行。在此运行期间,如果 effect 访问任何 signals,则会将其注册为这些 signals 的订阅者。一旦给定的函数运行完毕,当前订阅者将重置为其之前的值,以便在存在任何嵌套 effect 时,它们可以正确运行。
验证响应式系统
要验证系统,请以一秒的间隔递增 count
值:
这将以一秒的间隔在控制台上打印递增的计数值,以确认响应式系统的功能。
管理响应式系统中的生命周期
在响应式系统中,各种元素(通常称为“节点”)是相互连接的。这些节点可以是 signals、effects 或其他响应式原语。它们作为独立的单元共同构成系统的响应式行为。
当一个节点发生变化时,系统将重新评估连接到该节点的部件。这可能会导致连接的更新、添加或删除,从而影响系统的整体行为。
现在,考虑一个根据条件影响计算输出数据的场景:
在这个例子中,createMemo
用于缓存计算状态。这意味着如果其依赖项保持不变,则不必重新运行计算。
displayTemperature
memo 具有基于 displayTemp
值的提前返回条件。当 displayTemp
为 false
时,memo 会返回一条消息,指出“Temperature display is off”,因此不会跟踪 temperature
和 unit
。
但是,如果 unit
在 displayTemp
为 false
时发生更改,则不会触发该 effect,因为 memo 的当前依赖项(本例中为 displayTemp
)没有改变。
effect 跟踪是同步的
上述响应式系统同步运行。这个特性对于如何跟踪 effect 及其依项项有影响。具体来说,系统注册订阅者,运行 effect 函数,然后注销订阅者——所有这些都是以线性、同步的顺序进行的。
考虑以下示例:
这个例子中的 createEffect
函数启动 setTimeout
来延迟控制台日志。因为系统是同步的,所以它不会等待此操作完成。当 count
getter 在 setTimeout
内触发时,全局范围不再有注册订阅者。因此,这个 count
信号不会将回调添加为订阅者,这会导致跟踪 count
更改时可能会出现问题。
处理异步 effect
虽然基础响应式系统是同步的,但像 Solid 这样的框架提供了更高级的功能来处理异步场景。例如,on
函数提供了一种手动指定 effect 依赖项的方法。这对于确保异步操作正确地绑定到响应式系统中特别有用。
Solid 还引入了用于管理异步操作的 resources 概念。Resources 是专门的响应式原语,它将网络请求等操作的异步性转换为同步性,并将结果嵌入 signal 中。然后,系统可以跟踪异步操作及其状态,从而在操作完成或其状态更改时保持 UI 最新。
当涉及多个异步操作并且完成可能会影响响应式系统的不同部分时,使用 Solid 中的 Resources 可以在复杂的场景中提供帮助。通过将 resources 集成到系统中,您可以确保正确跟踪依赖项,并且 UI 与底层异步数据保持一致。