Skip to main content

svelte-patterns

Common Svelte patterns, best practices, and mistakes to avoid

ソース情報

リポジトリ
code-yeongyu/sisyphus-private
ソースの最終更新活動
2025年10月20日 01:49
検出された SKILL.md の言語
英語
スター
17
フォーク
2

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
svelte-patterns
description
Common Svelte patterns, best practices, and mistakes to avoid
# Svelte Patterns and Best Practices This skill covers common component patterns, frequently made mistakes, best practices, and migration tips for Svelte development. ## Component Patterns ### Prop Patterns ```svelte <!-- Basic props with defaults --> <script> let { title = 'Default Title', subtitle, isActive = false, items = [] } = $props(); </script> <h1>{title}</h1> {#if subtitle} <h2>{subtitle}</h2> {/if} <!-- Rest props pattern --> <script> let { class: className, ...restProps } = $props(); </script> <div class="container {className}" {...restProps}> <slot /> </div> ``` ### Event Handling Patterns ```svelte <!-- Custom event callbacks via props --> <script> let { onSubmit = () => {}, onChange = () => {}, onCancel } = $props(); let value = $state(''); function handleSubmit(event) { event.preventDefault(); onSubmit(value); } function handleChange(event) { value = event.target.value; onChange(value); } </script> <form onsubmit={handleSubmit}> <input type="text" value={value} oninput={handleChange} /> <button type="submit">Submit</button> {#if onCancel} <button type="button" onclick={onCancel}>Cancel</button> {/if} </form> ``` ### Snippet Pattern (Render Props) ```svelte <!-- Parent component --> <script> import DataList from './DataList.svelte'; let items = $state([ { id: 1, name: 'Alice', role: 'Developer' }, { id: 2, name: 'Bob', role: 'Designer' } ]); </script> <DataList {items}> {#snippet itemRenderer(item)} <div class="user-card"> <h3>{item.name}</h3> <p>{item.role}</p> </div> {/snippet} </DataList> <!-- DataList.svelte --> <script> let { items, children } = $props(); </script> <ul> {#each items as item} <li> {@render children.itemRenderer(item)} </li> {/each} </ul> ``` ### Context API Pattern ```svelte <!-- ThemeProvider.svelte --> <script> import { setContext } from 'svelte'; let { children } = $props(); let theme = $state('light'); setContext('theme', { get current() { return theme; }, toggle: () => { theme = theme === 'light' ? 'dark' : 'light'; } }); </script> <div class="theme-{theme}"> {@render children()} </div> <!-- ThemeConsumer.svelte --> <script> import { getContext } from 'svelte'; const themeContext = getContext('theme'); </script> <button onclick={themeContext.toggle}> Current theme: {themeContext.current} </button> ``` ### Composition Pattern ```svelte <!-- useCounter.svelte.js --> export function useCounter(initialValue = 0) { let count = $state(initialValue); return { get value() { return count; }, increment: () => count++, decrement: () => count--, reset: () => count = initialValue }; } <!-- Component.svelte --> <script> import { useCounter } from './useCounter.svelte.js'; const counter = useCounter(10); </script> <p>Count: {counter.value}</p> <button onclick={counter.increment}>+</button> <button onclick={counter.decrement}>-</button> <button onclick={counter.reset}>Reset</button> ``` ## Common Mistakes ### Mistake 1: Not Using Runes Properly ```svelte <!-- WRONG: Mixing old and new syntax --> <script> let count = 0; // Not reactive in Svelte 5! $: doubled = count * 2; // Old syntax function increment() { count += 1; // Won't trigger reactivity } </script> <!-- CORRECT: Use runes --> <script> let count = $state(0); let doubled = $derived(count * 2); function increment() { count += 1; } </script> ``` ### Mistake 2: Mutating Props Directly ```svelte <!-- WRONG: Mutating props --> <script> let { user } = $props(); function updateName(newName) { user.name = newName; // Don't mutate props! } </script> <!-- CORRECT: Use callbacks --> <script> let { user, onUpdateUser } = $props(); function updateName(newName) { onUpdateUser({ ...user, name: newName }); } </script> ``` ### Mistake 3: Side Effects in Derived ```svelte <!-- WRONG: Side effects in $derived --> <script> let count = $state(0); let doubled = $derived(() => { console.log('Calculating doubled'); // Side effect! localStorage.setItem('count', count); // Side effect! return count * 2; }); </script> <!-- CORRECT: Use $effect for side effects --> <script> let count = $state(0); let doubled = $derived(count * 2); $effect(() => { console.log('Count changed to:', count); localStorage.setItem('count', count.toString()); }); </script> ``` ### Mistake 4: Missing Effect Cleanup ```svelte <!-- WRONG: No cleanup --> <script> let isActive = $state(false); $effect(() => { if (isActive) { const interval = setInterval(() => { console.log('tick'); }, 1000); // Missing cleanup! Memory leak! } }); </script> <!-- CORRECT: Return cleanup function --> <script> let isActive = $state(false); $effect(() => { if (!isActive) return; const interval = setInterval(() => { console.log('tick'); }, 1000); return () => clearInterval(interval); }); </script> ``` ### Mistake 5: Incorrect Reactivity with Objects ```svelte <!-- WRONG: Reassigning nested properties --> <script> let user = $state({ name: 'Alice', settings: { theme: 'light' } }); function toggleTheme() { // This works but creates a new object unnecessarily user = { ...user, settings: { ...user.settings, theme: 'dark' } }; } </script> <!-- CORRECT: Direct mutation with $state --> <script> let user = $state({ name: 'Alice', settings: { theme: 'light' } }); function toggleTheme() { // $state provides deep reactivity user.settings.theme = user.settings.theme === 'light' ? 'dark' : 'light'; } </script> ``` ### Mistake 6: Overusing Effects ```svelte <!-- WRONG: Using effect for derived values --> <script> let count = $state(0); let doubled = $state(0); $effect(() => { doubled = count * 2; // This should be $derived! }); </script> <!-- CORRECT: Use $derived --> <script> let count = $state(0); let doubled = $derived(count * 2); </script> ``` ### Mistake 7: Not Handling Async Properly ```svelte <!-- WRONG: Race conditions --> <script> let searchQuery = $state(''); let results = $state([]); $effect(() => { fetch(`/api/search?q=${searchQuery}`) .then(res => res.json()) .then(data => { results = data; // May set stale results! }); }); </script> <!-- CORRECT: Handle cancellation --> <script> let searchQuery = $state(''); let results = $state([]); $effect(() => { const controller = new AbortController(); fetch(`/api/search?q=${searchQuery}`, { signal: controller.signal }) .then(res => res.json()) .then(data => results = data) .catch(err => { if (err.name !== 'AbortError') console.error(err); }); return () => controller.abort(); }); </script> ``` ## Best Practices ### Practice 1: Component Organization ```svelte <script> // 1. Imports import { getContext } from 'svelte'; import ChildComponent from './ChildComponent.svelte'; // 2. Props let { title, items = [], onItemClick } = $props(); // 3. Context const theme = getContext('theme'); // 4. State let selectedIndex = $state(0); let isExpanded = $state(false); // 5. Derived values let selectedItem = $derived(items[selectedIndex]); let itemCount = $derived(items.length); // 6. Effects $effect(() => { console.log('Selected item changed:', selectedItem); }); // 7. Functions function handleItemClick(index) { selectedIndex = index; onItemClick?.(items[index]); } function toggleExpanded() { isExpanded = !isExpanded; } </script> <!-- 8. Template --> <div class="component"> <!-- content --> </div> <!-- 9. Styles --> <style> .component { /* styles */ } </style> ``` ### Practice 2: Type Safety with TypeScript ```svelte <script lang="ts"> interface User { id: number; name: string; email: string; } let { users, onUserSelect }: { users: User[];
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る