DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

Svelte 日期快照不更新

SvelteDate 直接读取能更新,snapshot 派生结果却冻结,检查旧日期复制缺少依赖读取与 5.57.0 修复;普通快照仍是副本。

同一个 SvelteDate 每次都在改变,模板直接读取日期能够更新,放进 $state.snapshot() 后却像被冻结。这里要先区分两件事:快照读取的值是否正确,以及这次读取有没有成为响应式依赖。

Svelte 5.56.4 的日期快照路径存在追踪缺口。其他依赖触发重新计算时,快照会读到当前日期;仅日期变化时,它却没有理由重新计算。正式版 5.57.0 补上对应依赖读取,5.57.2 也包含修复。

snapshot 仍然是一次快照

$state.snapshot(date) 返回的是这次调用得到的普通日期副本,不是会一直跟随原对象变化的代理。即使升级后,在响应式上下文之外只调用一次,先前拿到的副本也不会自动更新。

应先核对数据来自 svelte/reactivity 的 SvelteDate,并确认应用调用了它的更新方法。普通 Date、普通对象中的日期字段,以及已经序列化的字符串,不能直接套用这项响应式结论。

然后看快照在哪里被读取。模板、$derived 或 effect 中的读取可以参与追踪;提前保存到普通常量再显示,是另一种一次性计算。若其他状态变化后快照立即变成新日期,而日期单独变化时不更新,就更符合这项依赖遗漏。

日期复制没有经过响应式读取

旧快照逻辑对 Date 使用结构化复制,但复制过程没有经过 SvelteDate 用来登记依赖的读取方法。直接调用 date.toISOString() 等日期读取路径能够建立关系,快照路径却可能绕过它。

已核对的正式修复在复制 Date 之前读取 getTime(),使反应上下文先订阅日期的变化,再生成当前副本。这没有把副本本身改造成响应式对象。

同样使用 snapshot 的 SvelteMap 可正常更新,也不能证明日期路径没有缺陷;不同类型在复制过程中触发的读取并不相同。

旧版本的窄范围处理

优先选择包含修复、并与项目兼容的正式版本。暂时不能升级、且应用确实需要在派生计算中生成日期快照时,可以在同一计算里先明确读取日期:

<script>
  import { SvelteDate } from 'svelte/reactivity';

  const date = new SvelteDate(0);
  let copy = $derived.by(() => {
    date.getTime();
    return $state.snapshot(date);
  });
</script>

<button onclick={() => date.setTime(date.getTime() + 60000)}>增加一分钟</button>
<p>{copy.toISOString()}</p>

这是为旧日期快照路径补依赖的组件示例,不是让所有 Date 都变成动态快照。读操作和快照应留在同一个有效计算中;在组件初始化时单独读一次 getTime(),不能保证后续计算继续订阅。

如果应用只是显示日期,原有的直接响应式读取也可以继续使用,不必为了绕行增加额外复制。保留业务需要的时区和格式,不要把刷新计时器或强制重建组件当成依赖追踪的修复。

只改变日期来验收

在受控环境中只更新 SvelteDate,确认对应派生快照会重新生成;再验证直接日期读取仍然正常。验收时暂时不要同时改变无关状态,否则它可能替缺失的依赖触发重新计算。

同时保留一个在计算外取得的旧副本,确认它仍表示原来的时间。快照应该保留这一语义,不能因为页面已经更新,就期待所有曾经交给外部库的副本也跟着变化。