Concepts

Effects

编辑此页面

Effects 是当它们所依赖的信号发生变化时触发的函数。它们在管理副作用方面发挥着至关重要的作用,副作用是指在应用程序范围之外发生的操作,例如 DOM 操作、数据获取和订阅。


使用 effect

使用 createEffect 函数创建 effect。该函数采用一个回调函数作为参数,该回调在 effect 被触发时运行。

import { createEffect } from "solid-js";
const [count, setCount] = createSignal(0);
createEffect(() => {
console.log(count());
});

在这个例子中,就创建了一个 effect,将 count 的当前值打印到控制台。当 count 的值发生变化时,会触发该 effect,使其再次运行并打印 count 的新值。


管理依赖关系

Effects 可以设置任意数量的依赖项。依赖项允许 effect 追踪改变并做出响应。这些可以包括信号、变量、props、上下文或其他响应值。当其中任何一个发生变化时,effect 都会接收通知,并将再次运行以更新状态。

初始化后,effect 将运行一次,无论它是否有任何依赖项。这对于设置 effect 和初始化变量或订阅信号非常有用。运行后,仅当其任何依赖项发生更改时才会再次触发 effect。

createEffect(() => {
console.log("hello"); // will run only once
});
createEffect(() => {
console.log(count()); // will run every time count changes
});

Solid 会自动追踪 effect 的依赖项,因此无需手动指定它们。这改善了追踪并最大限度地减少了忽略或错误识别依赖项的可能。


订阅信号

当 effect 被设置为观察一个信号时,它会创建对该信号的订阅。此订阅允许 effect 追踪信号值的变化,从而观察可能发生的任何变化并相应地执行其回调。

import { createSignal, createEffect } from "solid-js";
const [count, setCount] = createSignal(0);
createEffect(() => {
console.log(count()); // Logs current value of count whenever it changes
});

管理多个信号

Effect 具有观察多个信号的能力。单个 Effect 可以订阅多个信号,同样,多个 Effect 可以跟踪单个信号。当您需要根据多个信号更新 UI 时,这非常有用。

当在单个 Effect 中观察到多个信号时,只要任何信号发生变化,它将执行回调。即使只有一个信号发生变化(不一定是所有信号发生变化),效果也会运行。这意味着该 Effect 将以其正在观察的所有信号的最新值运行。

import { createSignal, createEffect } from "solid-js";
const [count, setCount] = createSignal(0);
const [message, setMessage] = createSignal("Hello");
createEffect(() => {
console.log(count(), message());
});
setCount(1); // Output: 1, "Hello"
setMessage("World"); // Output: 1, "World"

嵌套 effects

使用 effects 时,可以将它们相互嵌套。这允许每个 effect 独立跟踪其自身的依赖关系,而不影响其嵌套的效果。

createEffect(() => {
console.log("Outer effect starts");
createEffect(() => console.log("Inner effect"));
console.log("Outer effect ends");
});

需要注意执行顺序很重要。内部 effect 不会影响外部 effect。在内部 effect 中访问的信号不会注册为外部effect 的依赖项。当位于内部 effect 内的信号发生变化时,只会触发内部 effect 重新运行,而不会触发外部 effect 重新运行。

import { createSignal, createEffect } from "solid-js";
const [count, setCount] = createSignal(0);
createEffect(() => {
console.log("Outer effect starts");
createEffect(() => console.log(count())); // when count changes, only this effect will run
console.log("Outer effect ends");
});

这迫使每个 effect 彼此独立,这将有助于避免意外行为。此外,它还允许您创建仅在满足特定条件时触发的 effect。


生命周期函数

effect 具有可以使用某些函数进行管理的生命周期。这些函数允许您控制 effect 的初始化和处理,以构建您需要的行为类型。这可以包括仅运行一次副作用,或者在不再需要时清理任务。

onMount

onMount 在您只想运行一次副作用的情况下,可以使用 onMount 函数。此生命周期函数类似于 effect,但它不跟踪任何依赖项。相反,一旦组件初始化,onMount 回调将被执行并且不会再次运行。

import { onMount } from "solid-js";
function Component() {
const [data, setData] = createSignal(null);
createEffect(() => {
data(); // will run every time data changes
});
onMount(async () => {
// will run only once, when the component is mounted
const fetchedData = await fetch("https://example.com/data");
setData(fetchedData);
});
return <div>...</div>;
}

onMount 保证回调只会运行一次。如果在这种情况下使用 effect,则不能保证它只会运行一次,这可能会导致意外的行为。这使得 onMount 对于 API 调用和其他副作用非常有用,每个组件实例只需运行一次。

onCleanup

onMount 对于运行一次副作用很有用,而 onCleanup 对于不再需要任务时清理任务很有帮助。 onCleanup 将在组件卸载时运行,删除 effect 具有的订阅。

import { onCleanup } from "solid-js";
function App() {
const [count, setCount] = createSignal(0);
const timer = setInterval(() => {
setCount((prev) => prev + 1);
}, 1000);
onCleanup(() => {
clearInterval(timer);
});
return <div>Count: {count()}</div>;
}

在这个例子中,onCleanup 函数用于清除 effect 中设置的定时器。为了避免定时器无限期地运行,onCleanup 函数用于在组件卸载后清除定时器。

onCleanup 可用于避免内存泄漏。当组件被卸载但对其的引用仍然存在并且因此可能仍然在后台运行时,就会发生这些情况。使用 onCleanup 删除对该组件的任何订阅或引用可以帮助避免此问题。

报告此页面问题