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,确认对应派生快照会重新生成;再验证直接日期读取仍然正常。验收时暂时不要同时改变无关状态,否则它可能替缺失的依赖触发重新计算。
同时保留一个在计算外取得的旧副本,确认它仍表示原来的时间。快照应该保留这一语义,不能因为页面已经更新,就期待所有曾经交给外部库的副本也跟着变化。


