Basic Reactivity

createEffect

编辑此页面
import { createEffect } from "solid-js";
function createEffect<T>(fn: (v: T) => T, value?: T): void;

Effects 是一种在依赖项发生变化时运行任意代码("副作用")的通用方式,例如手动修改 DOM。 createEffect 创建一个新的计算,在跟踪作用域中运行给定的函数,自动跟踪其依赖项,并在依赖项更新时重新运行。

例如:

const [a, setA] = createSignal(initialValue);
// 依赖信号 `a` 的效应
createEffect(() => doSideEffect(a()));

a 的值发生变化时,副作用将会运行。

效应在创建后也会立即运行一次,以将 DOM 初始化为正确的状态。这被称为"挂载"阶段。 然而,我们建议使用 onMount 代替,这是一种更明确的表达方式。

效应回调可以返回一个值,该值将作为 prev 参数传递给效应的下一次调用。 这对于缓存昂贵的计算很有用。例如:

const [a, setA] = createSignal(initialValue);
// 依赖信号 `a` 的效应
createEffect((prevSum) => {
// 使用 `a` 和 `prevSum` 进行操作
const sum = a() + b();
if (sum !== prevSum) console.log("sum 变更为", sum);
return sum;
}, 0);
// ^ 效应的初始值为 0

效应主要用于从响应式系统读取但不写入的副作用:最好避免在效应中设置信号,因为这样做可能导致额外的渲染甚至无限的效应循环。相反,对于依赖其他响应式值的新值计算,请优先使用 createMemo,这样响应式系统就能知道什么依赖于什么,并相应地进行优化。

效应函数的第一次执行并不是立即的;它被安排在当前渲染阶段之后运行(即在传递给 rendercreateRootrunWithOwner 的函数返回之后)。 如果你想等待第一次执行发生,可以使用 queueMicrotask(在浏览器渲染 DOM 之前运行)或 await Promise.resolve()setTimeout(..., 0)(在浏览器渲染之后运行)。

// 假设这段代码在组件函数中,所以它是渲染阶段的一部分
const [count, setCount] = createSignal(0);
// 这个效应将在启动时和变化时打印 count
createEffect(() => console.log("count =", count()));
// 效应还未运行
console.log("hello");
setCount(1); // 效应仍未运行
setCount(2); // 效应仍未运行
queueMicrotask(() => {
// 现在打印 `count = 2`
console.log("microtask");
setCount(3); // 立即打印 `count = 3`
console.log("goodbye");
});
// --- 完整输出: ---
// hello
// count = 2
// microtask
// count = 3
// goodbye

第一次执行的这种延迟很有用,因为这意味着在组件作用域中定义的效应会在组件返回的 JSX 被添加到 DOM 之后运行。 特别是,refs 将已经被设置。 因此,你可以使用效应来手动操作 DOM、调用原生 JS 库或其他副作用。

注意,效应的第一次运行仍然在浏览器将 DOM 渲染到屏幕之前执行(类似于 React 的 useLayoutEffect)。 如果你需要等到渲染之后(例如,测量渲染结果),你可以使用 await Promise.resolve()(或 Promise.resolve().then(...)),但请注意,在 Promise 之后使用响应式状态(如信号)不会触发效应重运行,因为在异步函数中的 await 之后跟踪会丢失。 因此,你应该在 promise 之前使用所有依赖项。

如果你希望效应在第一次运行时立即执行,请使用 createRenderEffectcreateComputed

你可以通过在效应函数内部调用 onCleanup 来在效应之间清理操作。 这些清理函数会在效应执行之间和效应被销毁时(例如,当包含的组件卸载时)被调用。 例如:

// 动态监听由 eventName 信号提供的事件
createEffect(() => {
const event = eventName();
const callback = (e) => console.log(e);
ref.addEventListener(event, callback);
onCleanup(() => ref.removeEventListener(event, callback));
});

参数

  • fn - 在跟踪作用域中运行的函数。它可以返回一个值,该值将作为 prev 参数传递给效应的下一次调用。
  • value - 效应的初始值。这对于缓存昂贵的计算很有用。
报告此页面问题