createEffect
编辑此页面Effects 是一种在依赖项发生变化时运行任意代码("副作用")的通用方式,例如手动修改 DOM。
createEffect
创建一个新的计算,在跟踪作用域中运行给定的函数,自动跟踪其依赖项,并在依赖项更新时重新运行。
例如:
当 a
的值发生变化时,副作用将会运行。
效应在创建后也会立即运行一次,以将 DOM 初始化为正确的状态。这被称为"挂载"阶段。
然而,我们建议使用 onMount
代替,这是一种更明确的表达方式。
效应回调可以返回一个值,该值将作为 prev
参数传递给效应的下一次调用。
这对于缓存昂贵的计算很有用。例如:
效应主要用于从响应式系统读取但不写入的副作用:最好避免在效应中设置信号,因为这样做可能导致额外的渲染甚至无限的效应循环。相反,对于依赖其他响应式值的新值计算,请优先使用 createMemo,这样响应式系统就能知道什么依赖于什么,并相应地进行优化。
效应函数的第一次执行并不是立即的;它被安排在当前渲染阶段之后运行(即在传递给 render、createRoot 或 runWithOwner 的函数返回之后)。
如果你想等待第一次执行发生,可以使用 queueMicrotask(在浏览器渲染 DOM 之前运行)或 await Promise.resolve()
或 setTimeout(..., 0)
(在浏览器渲染之后运行)。
第一次执行的这种延迟很有用,因为这意味着在组件作用域中定义的效应会在组件返回的 JSX 被添加到 DOM 之后运行。 特别是,refs 将已经被设置。 因此,你可以使用效应来手动操作 DOM、调用原生 JS 库或其他副作用。
注意,效应的第一次运行仍然在浏览器将 DOM 渲染到屏幕之前执行(类似于 React 的 useLayoutEffect
)。
如果你需要等到渲染之后(例如,测量渲染结果),你可以使用 await Promise.resolve()
(或 Promise.resolve().then(...)
),但请注意,在 Promise 之后使用响应式状态(如信号)不会触发效应重运行,因为在异步函数中的 await 之后跟踪会丢失。
因此,你应该在 promise 之前使用所有依赖项。
如果你希望效应在第一次运行时立即执行,请使用 createRenderEffect 或 createComputed。
你可以通过在效应函数内部调用 onCleanup 来在效应之间清理操作。 这些清理函数会在效应执行之间和效应被销毁时(例如,当包含的组件卸载时)被调用。 例如:
参数
fn
- 在跟踪作用域中运行的函数。它可以返回一个值,该值将作为prev
参数传递给效应的下一次调用。value
- 效应的初始值。这对于缓存昂贵的计算很有用。