svelte-core-bestpractices by sveltejs/ai-tools
npx skills add https://github.com/sveltejs/ai-tools --skill svelte-core-bestpractices$state仅对需要具备响应式的变量使用 $state 运行符——换句话说,就是那些会导致 $effect、$derived 或模板表达式更新的变量。其他所有变量都可以是普通变量。
对象和数组($state({...}) 或 $state([...]))会被深度响应化,这意味着对它们的修改会触发更新。这有一个权衡:为了获得细粒度的响应性,这些对象必须被代理,这会带来性能开销。如果你处理的是仅被重新赋值(而非修改)的大型对象,请改用 $state.raw。例如,API 响应通常就属于这种情况。
$derived要从状态计算某些值,请使用 $derived 而不是 :
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
$effect// 这样做
let square = $derived(num * num);
// 不要这样做
let square;
$effect(() => {
square = num * num;
});
[!NOTE]
$derived接收一个表达式,而不是一个函数。如果你需要使用函数(例如,因为表达式很复杂),请使用$derived.by。
派生值是可写的——你可以像 $state 一样给它们赋值,不同之处在于当它们的表达式改变时,它们会重新计算。
如果派生表达式是一个对象或数组,它将按原样返回——它不会被深度响应化。但是,在极少数需要此功能的情况下,你可以在 $derived.by 内部使用 $state。
$effect效果是一种逃生舱口,应尽量避免使用。特别是,避免在效果内部更新状态。
{@attach ...} 会更简洁。$inspect。createSubscriber。永远不要将效果的内容包装在 if (browser) {...} 或类似的语句中——效果不会在服务器上运行。
$props将属性视为会发生变化。例如,依赖于属性的值通常应使用 $derived:
// @errors: 2451
let { type } = $props();
// 这样做
let color = $derived(type === 'danger' ? 'red' : 'green');
// 不要这样做——如果 `type` 改变,`color` 将不会更新
let color = type === 'danger' ? 'red' : 'green';
$inspect.trace$inspect.trace 是一个用于调试响应性的工具。如果某些内容没有正确更新或运行次数超出预期,你可以在 $effect 或 $derived.by(或它们调用的任何函数)的第一行添加 $inspect.trace(label),以追踪它们的依赖关系并发现是哪一个触发了更新。
任何以 on 开头的元素属性都被视为事件监听器:
<button onclick={() => {...}}>点击我</button>
<!-- 属性简写也有效 -->
<button {onclick}>...</button>
<!-- 展开属性也有效 -->
<button {...props}>...</button>
如果你需要将监听器附加到 window 或 document,你可以使用 <svelte:window> 和 <svelte:document>:
<svelte:window onkeydown={...} />
<svelte:document onvisibilitychange={...} />
避免为此使用 onMount 或 $effect。
片段是一种定义可重用标记块的方法,可以使用 {@render ...} 标签实例化,或作为属性传递给组件。它们必须在模板内声明。
{#snippet greeting(name)}
<p>你好 {name}!</p>
{/snippet}
{@render greeting('world')}
[!NOTE] 在组件顶层(即不在元素或块内部)声明的片段可以在
<script>内部引用。不引用组件状态的片段在<script module>中也可用,在这种情况下,它可以被导出供其他组件使用。
优先使用带键的 each 块——这通过允许 Svelte 精确地插入或删除项目(而不是更新属于现有项目的 DOM)来提高性能。
[!NOTE] 键必须唯一标识对象。不要使用索引作为键。
如果你需要修改项目(例如使用 bind:value={item.count} 这样的方式),请避免解构。
如果你有一个想在 CSS 内部使用的 JS 变量,你可以使用 style: 指令设置一个 CSS 自定义属性。
<div style:--columns={columns}>...</div>
然后你就可以在组件的 <style> 内部引用 var(--columns)。
组件 <style> 中的 CSS 作用域仅限于该组件。如果父组件需要控制子组件的样式,首选方式是使用 CSS 自定义属性:
<!-- Parent.svelte -->
<Child --color="red" />
<!-- Child.svelte -->
<h1>你好</h1>
<style>
h1 {
color: var(--color);
}
</style>
如果这不可能(例如,子组件来自库),你可以使用 :global 来覆盖样式:
<div>
<Child />
</div>
<style>
div :global {
h1 {
color: red;
}
}
</style>
考虑使用上下文,而不是在共享模块中声明状态。这将把状态作用域限定在应用程序需要它的部分,并消除在服务器端渲染时状态在用户之间泄漏的可能性。
使用 createContext 而不是 setContext 和 getContext,因为它提供了类型安全。
如果使用 5.36 或更高版本,你可以使用 await 表达式 和 hydratable 来直接在组件内部使用 Promise。请注意,这些功能需要在 svelte.config.js 中启用 experimental.async 选项,因为它们尚未被认为是完全稳定的。
始终为新代码使用运行符模式,并避免使用已有更现代替代方案的功能:
$state 而不是隐式响应性(例如 let count = 0; count += 1)$derived 和 $effect 而不是 $: 赋值和语句(但仅在无更好解决方案时使用效果)$props 而不是 export let、$$props 和 $$restPropsonclick={...} 而不是 on:click={...}{#snippet ...} 和 {@render ...} 而不是 <slot>、$$slots 和 <svelte:fragment><DynamicComponent> 而不是 <svelte:component this={DynamicComponent}>import Self from './ThisComponent.svelte' 和 <Self> 而不是 <svelte:self>$state 字段的类在组件之间共享响应性,而不是使用 store{@attach ...} 而不是 use:actionclass 属性中使用 clsx 风格的数组和对象,而不是 class: 指令每周安装量
417
代码仓库
GitHub 星标数
213
首次出现
2026年2月11日
安全审计
安装于
codex412
gemini-cli401
cursor390
opencode388
github-copilot387
kimi-cli385
$stateOnly use the $state rune for variables that should be reactive — in other words, variables that cause an $effect, $derived or template expression to update. Everything else can be a normal variable.
Objects and arrays ($state({...}) or $state([...])) are made deeply reactive, meaning mutation will trigger updates. This has a trade-off: in exchange for fine-grained reactivity, the objects must be proxied, which has performance overhead. In cases where you're dealing with large objects that are only ever reassigned (rather than mutated), use $state.raw instead. This is often the case with API responses, for example.
$derivedTo compute something from state, use $derived rather than $effect:
// do this
let square = $derived(num * num);
// don't do this
let square;
$effect(() => {
square = num * num;
});
[!NOTE]
$derivedis given an expression, not a function. If you need to use a function (because the expression is complex, for example) use$derived.by.
Deriveds are writable — you can assign to them, just like $state, except that they will re-evaluate when their expression changes.
If the derived expression is an object or array, it will be returned as-is — it is not made deeply reactive. You can, however, use $state inside $derived.by in the rare cases that you need this.
$effectEffects are an escape hatch and should mostly be avoided. In particular, avoid updating state inside effects.
{@attach ...}$inspectcreateSubscriberNever wrap the contents of an effect in if (browser) {...} or similar — effects do not run on the server.
$propsTreat props as though they will change. For example, values that depend on props should usually use $derived:
// @errors: 2451
let { type } = $props();
// do this
let color = $derived(type === 'danger' ? 'red' : 'green');
// don't do this — `color` will not update if `type` changes
let color = type === 'danger' ? 'red' : 'green';
$inspect.trace$inspect.trace is a debugging tool for reactivity. If something is not updating properly or running more than it should you can add $inspect.trace(label) as the first line of an $effect or $derived.by (or any function they call) to trace their dependencies and discover which one triggered an update.
Any element attribute starting with on is treated as an event listener:
<button onclick={() => {...}}>click me</button>
<!-- attribute shorthand also works -->
<button {onclick}>...</button>
<!-- so do spread attributes -->
<button {...props}>...</button>
If you need to attach listeners to window or document you can use <svelte:window> and <svelte:document>:
<svelte:window onkeydown={...} />
<svelte:document onvisibilitychange={...} />
Avoid using onMount or $effect for this.
Snippets are a way to define reusable chunks of markup that can be instantiated with the {@render ...} tag, or passed to components as props. They must be declared within the template.
{#snippet greeting(name)}
<p>hello {name}!</p>
{/snippet}
{@render greeting('world')}
[!NOTE] Snippets declared at the top level of a component (i.e. not inside elements or blocks) can be referenced inside
<script>. A snippet that doesn't reference component state is also available in a<script module>, in which case it can be exported for use by other components.
Prefer to use keyed each blocks — this improves performance by allowing Svelte to surgically insert or remove items rather than updating the DOM belonging to existing items.
[!NOTE] The key must uniquely identify the object. Do not use the index as a key.
Avoid destructuring if you need to mutate the item (with something like bind:value={item.count}, for example).
If you have a JS variable that you want to use inside CSS you can set a CSS custom property with the style: directive.
<div style:--columns={columns}>...</div>
You can then reference var(--columns) inside the component's <style>.
The CSS in a component's <style> is scoped to that component. If a parent component needs to control the child's styles, the preferred way is to use CSS custom properties:
<!-- Parent.svelte -->
<Child --color="red" />
<!-- Child.svelte -->
<h1>Hello</h1>
<style>
h1 {
color: var(--color);
}
</style>
If this is impossible (for example, the child component comes from a library) you can use :global to override styles:
<div>
<Child />
</div>
<style>
div :global {
h1 {
color: red;
}
}
</style>
Consider using context instead of declaring state in a shared module. This will scope the state to the part of the app that needs it, and eliminate the possibility of it leaking between users when server-side rendering.
Use createContext rather than setContext and getContext, as it provides type safety.
If using version 5.36 or higher, you can use await expressions and hydratable to use promises directly inside components. Note that these require the experimental.async option to be enabled in svelte.config.js as they are not yet considered fully stable.
Always use runes mode for new code, and avoid features that have more modern replacements:
$state instead of implicit reactivity (e.g. let count = 0; count += 1)$derived and $effect instead of $: assignments and statements (but only use effects when there is no better solution)$props instead of export let, $$props and $$restPropsonclick={...} instead of on:click={...}Weekly Installs
417
Repository
GitHub Stars
213
First Seen
Feb 11, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex412
gemini-cli401
cursor390
opencode388
github-copilot387
kimi-cli385
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
105,000 周安装
React extract-errors 工具:自动提取和分配错误代码,提升开发效率
788 周安装
React性能优化指南:记忆化、代码分割、虚拟化与高效渲染策略
805 周安装
Twitter阅读器 - 无需JS和身份验证获取Twitter/X帖子内容 | Jina API集成
782 周安装
Railway 域名管理技能:添加、查看、移除自定义域名和 Railway 域名
766 周安装
CloudBase 文档数据库微信小程序 SDK 使用指南 - 腾讯云开发数据操作教程
816 周安装
问题定义框架 | 91位产品负责人方法论,区分问题与解决方案,避免AI技术陷阱
803 周安装
{#snippet ...} and {@render ...} instead of <slot> and $$slots and <svelte:fragment><DynamicComponent> instead of <svelte:component this={DynamicComponent}>import Self from './ThisComponent.svelte' and <Self> instead of <svelte:self>$state fields to share reactivity between components, instead of using stores{@attach ...} instead of use:actionclass attributes, instead of the class: directive