如何创建延迟底层信号并立即清除的信号

How to create a signal that delays the underlying signal and clears immediately

我想制作一个信号,在一定延迟后将其自身设置为底层信号或备忘录,并在底层信号被清除后立即清除。下面的代码演示了我想要的。

import { render } from "solid-js/web";
import { For, createSignal, createEffect } from "solid-js";

function Counter() {
   const [s, setS] = createSignal(undefined)
   const [delayedS, delayedSetS] = createSignal(undefined)


   setTimeout(() => {
     setS(10)
   }, 1000)

   setTimeout(() => {
     setS(undefined)
   }, 3000)

   createEffect(() => {
      let res = s()
      if (res !== undefined) {
         setTimeout(() => delayedSetS(res), 1000)
      } else {
         delayedSetS(undefined)
      }
   })

  return (<>
    <span> S {s()} </span>
    <span> Delayed S {delayedS()}</span>
    </>)
}

render(() => <Counter />, document.getElementById("app"));

这可行,但这是一种正确的方法吗?我不确定 createDeferred 是否提供此功能,但我不想使用它,因为它使用调度程序我不确定它的作用。

您的尝试完全有效。

createDeferred,虽然它看起来像是有类似的用例,但它不会按预期在这里工作,因为:

  1. 传递给 createDeferred 的超时时间不是在导致更新之前等待的准确时间量 – 它是浏览器空闲之前等待的最大超时时间。
  2. 在将信号更新为 undefined 和其他值之前会发生超时。
const delayedS = createDeferred(s)

设置信号的首选原语是createComputed。这是一个纯粹的计算——类似于 createMemo——这意味着它会在效果之前立即 运行。在简单示例中,效果的使用通常没有区别,但使用效果设置信号可能会导致不必要的更新。

  createComputed(
    on(s, (v) => {
      if (v) setTimeout(() => setDelayedS(v), 1000);
      else setDelayedS();
    })
  );

另外清除设置上的超时 undefined 没有延迟发生,可以消除一些计时故障。

  let timeoutId = 0;
  createComputed(
    on(s, (v) => {
      if (v) timeoutId = setTimeout(() => setDelayedS(v), 1000);
      else {
        setDelayedS();
        clearTimeout(timeoutId);
      }
    })
  );
  onCleanup(() => clearTimeout(timeoutId));