前言
Solid.js,一个比 React 更 react 的框架。每一个使用 React 的同学,你可以不使用,但不应该不了解。
目前 Solid.js 发布了最新的官方文档,但却缺少对应的中文文档。为了帮助大家学习 Solid.js,为爱发电翻译文档。
我同时搭建了 Solid.js 最新的中文文档站点:solid.yayujs.com ,欢迎勘误。
虽说是翻译,但个人并不喜欢严格遵守原文,为了保证中文阅读流畅,会删减部分语句,对难懂的部分也会另做补充解释,希望能给大家带来一个好的中文学习体验。
欢迎围观朋友圈、加入低调务实优秀中国好青年前端社群,一个人走得快,一群人走得远。
派生信号
派生信号是依赖一个或多个信号来产生值的函数。
这些函数不会立即执行,而是仅在它们所依赖的值发生改变时才被调用。当底层信号改变时,该函数将被再次调用以产生新值。
javascript
const double = () => count() * 2;
在上面的示例中,double
函数依赖于 count
信号来生成值。当 count
信号改变时,double
函数将被再次调用以产生新值。
同样,您可以创建依赖于 store 的派生信号,因为 store 幕后也是使用信号。要了解有关 store 如何运作,您可以访问store 章节。
javascript
const fullName = () => store.firstName + ' ' + store.lastName;
这些依赖函数从它们访问的信号中获得响应式,确保底层数据的更改在整个应用程序中传播。需要注意的是,这些函数本身并不存储值;相反, 它们可以更新依赖于它们的任何 effect 或组件。如果包含在组件主体中,这些派生信号将在必要时触发更新。
虽然您可以通过这种方式创建派生值,但 Solid 创建了 createMemo。要更深入地了解 memos 如何工作,请查看 memos 章节。
Memos
Memos 是一种响应式值,用于记忆化派生装填或昂贵计算。它们与派生信号类似于,因为它们都是响应式值,当它们的依赖关系发生变化时,会自动重新评估。然而,与派生信号不同,memos 经过优化,只对其依赖项的每次更改执行一次。
Memos 提供一个只读响应式值(类似于信号),并跟踪其依赖项的变化(类似于效果)。这使得它们对于昂贵计算或频繁访问的计算结果非常有用。通过这样做,memos 会保留计算记过直到其依赖项发生变化,从而最大限度的减少应用程序中不必要的工作。
使用 memos
使用 createMemo
函数创建一个 memo。在此函数中,您可以定义你希望记忆化的派生值或者计算。调用时,createMemo
将返回一个 getter 函数,该函数用于读取 memo 的当前值:
jsx
import { createMemo, createSignal } from "solid-js"
const [count, setCount] = createSignal(0)
const isEven = createMemo(() => count() % 2 === 0)
console.log(isEven()) // true
setCount(3)
console.log(isEven()) // false
虽然 memo 看起来与 effect 相似,但它们的不同之处在于它们返回一个值。该值是您希望记住的计算结果或派生状态。
使用 memos 的优势
虽然您可以使用派生信号来获得类似的结果,但 memos 具有明显的优势:
- Memos 经过优化,只对其依赖项的每次更改执行一次
- 当处理昂贵的计算时,可以使用 memos 缓存结果,这样就不会不必要地重新计算它们。
- memos 仅在其依赖项发生变化时才会重新计算,并且如果其依赖项发生变化但其值保持不变,则不会触发后续更新(由 === 或严格相等确定)。
- memos 函数中的任何信号或 memo 都会被追踪。这意味着当这些依赖项发生变化时,memos 将自动重新评估。
Memo vs. effect
在管理响应式计算和副作用时,Memo 和 effect 都很重要。然而,它们有不同的目的,并且各自有自己独特的行为。
Memos | Effects | |
---|---|---|
返回值 | 是 - 返回计算结果或派生状态的 getter。 | 不返回值,但执行代码块以响应更改。 |
缓存结果 | 是 | 否 |
行为 | 函数参数应该是纯的,没有响应式副作用。 | 函数参数可能会导致 UI 更新或数据获取等副作用。 |
依赖追踪 | 是 | 是 |
示例用例 | 转换数据结构、计算聚合值、派生状态或其他昂贵的计算。 | UI 更新、网络请求或外部集成 |
最佳实践
纯函数
使用 memos 时,建议您将其写为纯函数:
jsx
import { createSignal, createMemo } from "solid-js"
const [count, setCount] = createSignal(0)
const isEven = createMemo(() => count() % 2 === 0) // 一个纯函数示例
纯函数是指不会导致任何副作用的函数。这意味着函数的输出应该仅取决于其输入。
当您在 memos 中引入副作用时,它会使反应链变得复杂。这可能会导致意外行为,例如无限循环,从而导致应用程序崩溃。
jsx
import { createSignal, createMemo } from "solid-js"
const [count, setCount] = createSignal(0)
const [message, setMessage] = createSignal("")
const badMemo = createMemo(() => {
if (count() > 10) {
setMessage("Count is too high!") // 副作用
}
return count() % 2 === 0
})
当 memos 具有导致其依赖关系发生变化的副作用时,可能会触发无限循环。这将导致 memos 重新评估,然后再次触发副作用,依此类推,直到应用程序崩溃。
可以通过使用 createEffect 来处理副作用来避免这种情况:
jsx
import { createSignal, createMemo, createEffect } from "solid-js"
const [count, setCount] = createSignal(0)
const [message, setMessage] = createSignal("")
const isEven = createMemo(() => count() % 2 === 0)
createEffect(() => {
if (count() > 10) {
setMessage("Count is too high!")
}
})
在这里, createEffect
将处理副作用,而 isEven
memo 将保持为纯函数。
在 memos 中保留逻辑
Memos 经过优化,只会对其依赖项的每次改变执行一次。这意味着您可以删除由 Memos 的依赖项触发的不必要的效果。
在处理派生状态时,Memos 是优于 effects 的推荐方法。将逻辑保留在 Memos 中可以防止使用 effects 时可能发生的不必要的重新渲染。同样,effects 更适合处理副作用,例如 DOM 更新,而不是派生状态。这种关注点分离可以帮助保持代码整洁且易于理解。
jsx
// effect - 无论何时 `count` 改变都会运行
createEffect(() => {
if (count() > 10) {
setMessage("Count is too high!")
} else {
setMessage("")
}
})
// memo - 只有当 `count` 改变到值大于 10 ,才会运行
const message = createMemo(() => {
if (count() > 10) {
return "Count is too high!"
} else {
return ""
}
})
系列文章
本篇已收录在掘金专栏 《Solid.js 中文文档》。
此外我还写过 React 系列、TypeScript 系列、Next.js 系列、VuePress 博客搭建系列、JavaScript 系列等多个系列文章,全系列文章目录:github.com/mqyqingfeng...
通过文字建立交流本身就是一种缘分,欢迎围观朋友圈、加入低调务实优秀中国好青年前端社群,一个人走得快,一群人走得远。