运行时警告
客户端警告
assignment_value_stale
对 `%property%` 属性 (%location%) 的赋值将计算右侧,而不是赋值后 `%property%` 的值。这可能导致意外行为。
考虑这样一个情况...
<script>
let object = $state({ array: null });
function add() {
(object.array ??= []).push(object.array.length);
}
</script>
<button onclick={add}>添加</button>
<p>项目: {JSON.stringify(object.items)}</p>
...当按钮第一次被点击时,正在推送到的数组是赋值右侧的 []
,但 object.array
的最终值是一个空的状态代理。因此,被推送的值将被丢弃。
你可以通过将其分为两个语句来修复此问题:
function function add(): void
add() {
let object: {
array: number[];
}
object.array: number[]
array ??= [];
let object: {
array: number[];
}
object.array: number[]
array.Array<number>.push(...items: number[]): number
Appends new elements to the end of an array, and returns the new length of the array.
push(let object: {
array: number[];
}
object.array: number[]
array.Array<number>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length);
}
binding_property_non_reactive
`%binding%` 绑定到非响应式属性
`%binding%` (%location%) 绑定到非响应式属性
console_log_state
你的 `console.%method%` 包含了 `$state` 代理。考虑使用 `$inspect(...)` 或 `$state.snapshot(...)` 代替
在记录一个 代理 时,浏览器开发工具将记录代理本身,而不是它所表示的值。在 Svelte 中,$state
代理的“目标”可能与其当前值不符,这可能会造成混淆。
记录一个值随着时间变化的最简单方法是使用 $inspect
符文。或者,为了临时记录某些事情(例如,在事件处理程序内部)你可以使用 $state.snapshot
来获取当前值的快照。
event_handler_invalid
%handler% 应该是一个函数。你是想 %suggestion% 吗?
hydration_attribute_changed
在服务器和客户端渲染之间,`%html%` 上的 `%attribute%` 属性更改了其值。客户端值 `%value%` 将被忽略,以服务器值为准
某些属性(如<img>
元素上的 src
)在水合期间不会被修复,即服务器值将被保留。这是因为更新这些属性可能导致图像被重新获取(或者在 <iframe>
的情况下,框架被重新加载),即使它们解析到相同的资源。
要解决此问题,可以用 svelte-ignore
注释来静默此警告,或者确保在服务器和客户端之间值保持不变。如果你确实需要在水合时更改值,可以像这样强制更新:
<script>
let { src } = $props();
if (typeof window !== 'undefined') {
// 储存该值...
const initial = src;
// 取消设置...
src = undefined;
$effect(() => {
// ...在我们挂载之后重置
src = initial;
});
}
</script>
<img {src} />
hydration_html_changed
`{@html ...}` 块在服务器和客户端渲染之间的值发生更改。客户端值将被忽略,以服务器值为准
`{@html ...}` 块 %location% 在服务器和客户端渲染之间的值发生更改。客户端值将被忽略,以服务器值为准
如果 {@html ...}
的值在服务器和客户端之间发生变化,它将在水合期间不会被修复,即服务器值将被保留。这是因为在水合期间的变更检测成本高昂且通常是不必要的。
要解决此问题,可以用 svelte-ignore
注释来静默此警告,或者确保在服务器和客户端之间值保持不变。如果你确实需要在水合时更改值,可以像这样强制更新:
<script>
let { markup } = $props();
if (typeof window !== 'undefined') {
// 储存该值...
const initial = markup;
// 取消设置...
markup = undefined;
$effect(() => {
// ...在我们挂载之后重置
markup = initial;
});
}
</script>
{@html markup}
hydration_mismatch
水合失败,因为初始 UI 与服务器上渲染的内容不匹配
水合失败,因为初始 UI 与服务器上渲染的内容不匹配。错误发生在 %location% 附近
当 Svelte 在水合来自服务器的 HTML 时遇到错误时,会抛出此警告。在水合期间,Svelte 遍历 DOM,期望特定结构。如果该结构不同(例如,因为无效 HTML 导致 HTML 被 DOM 修复),那么 Svelte 将遇到问题,从而导致此警告。
在开发过程中,此错误通常会伴随一个 console.error
,详细说明需要修复的 HTML。
invalid_raw_snippet_render
传递给 `createRawSnippet` 的 `render` 函数应该返回单个元素的 HTML
legacy_recursive_reactive_block
检测到在 `%filename%` 中迁移的 `$:` 响应式块,该块同时访问和更新同一响应式值。这可能会在转换为 `$effect` 时导致递归更新。
lifecycle_double_unmount
尝试卸载未挂载的组件
ownership_invalid_binding
%parent% 用 `bind:` 向 %child% 传递了一个值,但该值由 %owner% 所拥有。考虑在 %owner% 和 %parent% 之间创建一个绑定
考虑三个组件 GrandParent
、Parent
和 Child
。如果你做 <GrandParent bind:value>
,在 GrandParent
内通过 <Parent {value} />
(注意缺少 bind:
)传递变量,然后在 Parent
内做 <Child bind:value>
,就会抛出此警告。
要解决它,应该 bind:
该值,而不是仅仅传递一个属性(即在这个例子中做 <Parent bind:value />
)。
ownership_invalid_mutation
在创建它的组件之外修改一个值是强烈不建议的。考虑使用 `bind:` 向子组件传递值,或使用回调
%component% 修改了由 %owner% 所拥有的值。这是强烈不建议的。考虑使用 `bind:` 向子组件传递值,或使用回调
考虑以下代码:
<script>
import Child from './Child.svelte';
let person = $state({ name: 'Florida', surname: 'Man' });
</script>
<Child {person} />
<script lang="ts">
import Child from './Child.svelte';
let person = $state({ name: 'Florida', surname: 'Man' });
</script>
<Child {person} />
<script>
let { person } = $props();
</script>
<input bind:value={person.name}>
<input bind:value={person.surname}>
<script lang="ts">
let { person } = $props();
</script>
<input bind:value={person.name}>
<input bind:value={person.surname}>
Child
正在修改由 App
所拥有的 person
,而没有被明确“允许”这样做。这是强烈不建议的,因为这可能会导致难以进行推理的代码(“谁修改了这个值?”),因此出现警告。
要解决此问题,可以创建回调属性来传达更改,或将 person
标记为 $bindable
。
state_proxy_equality_mismatch
响应式 `$state(...)` 代理和它们代理的值具有不同的身份。由于这个原因,与 `%operator%` 的比较将产生意想不到的结果
$state(...)
创建了一个 代理 对它所传递的值。代理和该值具有不同的身份,这意味着相等性检查将始终返回 false
:
<script>
let value = { foo: 'bar' };
let proxy = $state(value);
value === proxy; // 始终为 false
</script>
为了解决此问题,请确保比较的值都是通过 $state(...)
创建的,或者都不是。请注意,$state.raw(...)
不会创建状态代理。
共享警告
dynamic_void_element_content
`<svelte:element this="%tag%">` 是一个空元素 —— 它不能有内容
像 <input>
这样的元素不能有内容,传递给这些元素的任何子元素将被忽略。
state_snapshot_uncloneable
值无法通过 `$state.snapshot` 克隆 —— 返回的是原始值
以下属性无法通过 `$state.snapshot` 克隆 —— 返回值包含原始值:
%properties%
$state.snapshot
试图克隆给定值,以返回一个不再变化的引用。某些对象可能不可克隆,在这种情况下,将返回原始值。在以下示例中,property
被克隆,但 window
不被克隆,因为 DOM 元素不可克隆:
const const object: {
property: string;
window: Window & typeof globalThis;
}
object = function $state<{
property: string;
window: Window & typeof globalThis;
}>(initial: {
property: string;
window: Window & typeof globalThis;
}): {
property: string;
window: Window & typeof globalThis;
} (+1 overload)
namespace $state
$state({ property: string
property: 'this is cloneable', window: Window & typeof globalThis
window });
const const snapshot: {
property: string;
window: {
[x: number]: {
[x: number]: ...;
readonly clientInformation: {
readonly clipboard: {
read: {};
readText: {};
write: {};
writeText: {};
addEventListener: {};
dispatchEvent: {};
removeEventListener: {};
};
... 41 more ...;
readonly storage: {
...;
};
};
... 207 more ...;
readonly sessionStorage: {
...;
};
};
... 921 more ...;
undefined: undefined;
};
}
snapshot = namespace $state
function $state<T>(initial: T): T (+1 overload)
$state.function $state.snapshot<{
property: string;
window: Window & typeof globalThis;
}>(state: {
property: string;
window: Window & typeof globalThis;
}): {
property: string;
window: {
...;
};
}
To take a static snapshot of a deeply reactive $state
proxy, use $state.snapshot
:
Example:
<script>
let counter = $state({ count: 0 });
function onclick() {
// Will log `{ count: ... }` rather than `Proxy { ... }`
console.log($state.snapshot(counter));
};
</script>
snapshot(const object: {
property: string;
window: Window & typeof globalThis;
}
object);