DEBUG.WIKI
OnlineSIM:在线接收短信,虚拟号码租用
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →

Svelte 给 $state.toString 赋值后字段消失:先检查原型同名键

Svelte 5.57.2 的状态代理可能丢弃后来添加的原型同名字段,SSR 与客户端也会分歧。初始化为自有字段可作局部处理,但不等于修复任意动态键。

向 $state({}) 写入 toString 后,Object.hasOwn 仍为 false,JSON 里也没有该字段。若普通字段能正常保存,检查名字是否与对象原型成员相同。

Svelte 5.57.2 的这一条件不只是页面没更新。给起初为空的代理赋值 state.toString = 'own',值可能根本没有进入状态;读取仍是继承来的函数,快照、展开与序列化也看不到新字段。valueOf、constructor 等原型同名键也需按同样条件排查。

先确认是值没写入,还是查询没追踪

在已有诊断中,对照同一时刻的直接读取、自有属性判断及序列化结果。若值已经在对象里,只有响应式页面停留在旧布尔值,应另查属性查询的依赖追踪;本题的关键是后来添加的同名键被丢弃。

5.57.2 的 set trap 用 prop in target 判断键是否已存在。继承键会让结果为 true,但目标上又没有该键的自有可写描述,创建响应式 source 的分支因此被跳过。这个差别解释了为何普通新字段能写,而已有原型名字不行。

已知字段可在创建状态时明确提供

如果业务确实有名为 toString 的数据字段,且字段集合已知,可以在状态初始化时就把它定义为自有字段:

<script>
  let fields = $state({ toString: '' });
</script>

<input bind:value={fields.toString} />
<p>{JSON.stringify(fields)}</p>

这样后续更新面对的是已经存在的自有可写字段,而不是后来才要遮蔽的继承成员。保留真实字段名和服务端协议;若字段是可选的,预置空字符串会改变“字段缺失”的语义,必须先确认提交和校验约定允许。不能把所有可选字段都悄悄补为空值。

拥有字符串 toString 的普通对象本来也会改变字符串转换行为,所以不要再依赖 String(fields) 调用默认方法。这里处理的是业务字段,不是给对象实现新的转换函数。

如果表单库负责在内部创建状态,单独在组件中初始化另一个对象不会修复库内部的写入。应在库支持的初值入口提供字段,或等待并采用经核对的正式修正。对于任意动态外部键,设计明确的数据容器和输入边界,不能靠预列几个名字宣称全部解决。

同时检查 SSR、客户端和提交值

SSR 的 $state 不经过同样的客户端代理,初始化期间的写入可能在服务端保留、水合后丢失。检查服务端 HTML、客户端交互及真正提交给后端的值,尤其注意页面看似能输入但提交仍为空的情况。

覆盖初值、修改、序列化和原有可选字段逻辑。不要用 delete state.toString 清理现场:该版本删除继承键还有另一条行为差异,可能让原型成员也无法正常读取。当前正式 5.57.2 仍保留相关 set 判断;较早的 hasOwn 追踪修正不代表这个赋值缺口也已消失。