Derived Values

Memos

编辑此页面

Memos 是一种响应式值,用于记忆化派生装填或昂贵计算。它们与派生信号类似于,因为它们都是响应式值,当它们的依赖关系发生变化时,会自动重新评估。然而,与派生信号不同,memos 经过优化,只对其依赖项的每次更改执行一次。

Memos 提供一个只读响应式值(类似于信号),并跟踪其依赖项的变化(类似于效果)。这使得它们对于昂贵计算或频繁访问的计算结果非常有用。通过这样做,memos 会保留计算记过直到其依赖项发生变化,从而最大限度的减少应用程序中不必要的工作。


使用 memos

使用 createMemo 函数创建一个 memo。在此函数中,您可以定义你希望记忆化的派生值或者计算。调用时,createMemo将返回一个 getter 函数,该函数用于读取 memo 的当前值:

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 都很重要。然而,它们有不同的目的,并且各自有自己独特的行为。

MemosEffects
返回值是 - 返回计算结果或派生状态的 getter。不返回值,但执行代码块以响应更改。
缓存结果
行为函数参数应该是纯的,没有响应式副作用。函数参数可能会导致 UI 更新或数据获取等副作用。
依赖追踪
示例用例转换数据结构、计算聚合值、派生状态或其他昂贵的计算。UI 更新、网络请求或外部集成

最佳实践

纯函数

使用 memos 时,建议您将其写为纯函数:

import { createSignal, createMemo } from "solid-js";
const [count, setCount] = createSignal(0);
const isEven = createMemo(() => count() % 2 === 0); // example of a pure function

纯函数是指不会导致任何副作用的函数。这意味着函数的输出应该仅取决于其输入。

当您在 memos 中引入副作用时,它会使反应链变得复杂。这可能会导致意外行为,例如无限循环,从而导致应用程序崩溃。

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!"); // side effect
}
return count() % 2 === 0;
});

当 memos 具有导致其依赖关系发生变化的副作用时,可能会触发无限循环。这将导致 memos 重新评估,然后再次触发副作用,依此类推,直到应用程序崩溃。

可以通过使用 createEffect 来处理副作用来避免这种情况:

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 更新,而不是派生状态。这种关注点分离可以帮助保持代码整洁且易于理解。

// 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 "";
}
});
报告此页面问题