コンテンツにスキップ

React使いが語るSvelteなら〇〇が要らない

File ID: 20241206214713.mdx

まとめ

  • clsxが要らない
  • hoge.module.cssが要らない
  • Framer Motionが要らない
  • setHogeが要らない
  • 状態管理ライブラリが要らない
  • 依存配列が要らない
  • pathpidaが要らない
  • Tanstack Query(SWR)が要らない

clsxが要らない

<!-- These are equivalent -->
<div class={isCool ? "cool" : ""}>...</div>
<div class:cool={isCool}>...</div>
<!-- These are equivalent -->
<div style:color="red">...</div>
<div style="color: red">...</div>

hoge.module.cssが要らない

<style>
.bouncy {
animation: bounce 10s;
}
/* these keyframes are only accessible inside this component */
@keyframes bounce {
/* ... */
}
</style>

しかも未使用のCSSを
静的解析で検出できる!


CSS変数の扱いに長けている

<Slider
bind:value
min={0}
max={100}
--track-color="black"
--thumb-color="rgb({r} {g} {b})"
/>
<svelte-css-wrapper
style="display: contents; --track-color: black; --thumb-color: rgb({ r } { g } { b })"
>
<Slider
bind:value
min={0}
max={100}
/>
</svelte-css-wrapper>

※ SliderコンポーネントのPropsに
渡すわけではない


もし構造を維持したいなら(標準タグが使える場合)

<input
bind:value
type="range"
min={0}
max={100}
style:--track-color="black"
style:--thumb-color="rgb({r} {g} {b})"
/>

Framer Motionが要らない

表示非表示

<script>
import { fade } from "svelte/transition";
let visible = $state(false);
</script>
<button onclick={() => visible = !visible}>toggle</button>
{#if visible}
<div transition:fade>fades in and out</div>
{/if}

リストのアニメーション

<!-- When `list` is reordered the animation will run -->
{#each list as item, index (item)}
<li animate:flip>{item}</li>
{/each}

setHogeが要らない

<script>
let count = $state(0);
</script>
<button onclick={() => count++}>
clicks: {count}
</button>

いわゆるSignal的な実装


状態管理ライブラリが要らない

export const myGlobalState = $state({
user: {
/* ... */
},
/* ... */
});
<script>
import { myGlobalState } from "./state.svelte";
// ...
</script>;

Signalはどこでも定義可能

自然とJotaiっぽくなる


依存配列が要らない

$derived(useMemo)

<script>
let numbers = $state([1, 2, 3]);
let total = $derived.by(() => {
let total = 0;
for (const n of numbers) {
total += n;
}
return total;
});
</script>
<button onclick={() => numbers.push(numbers.length + 1)}>
{numbers.join(" + ")} = {total}
</button>

$effect(useEffect)

<script>
let size = $state(50);
let color = $state("#ff3e00");
let canvas;
$effect(() => {
const context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
// this will re-run whenever `color` or `size` change
context.fillStyle = color;
context.fillRect(0, 0, size, size);
});
</script>
<canvas bind:this={canvas} width="100" height="100" />

依存に含めたくない場合は
untrack関数を使います


pathpidaが要らない

要検証(まだ自分も把握しきれてない)

<script lang="ts">
import type { PageData } from "./$types";
let { data }: { data: PageData } = $props();
</script>

https://svelte.dev/docs/kit/types


Tanstack Query(SWR)が要らない

{#await promise}
<!-- promise is pending -->
<p>waiting for the promise to resolve...</p>
{:then value}
<!-- promise was fulfilled or not a Promise -->
<p>The value is {value}</p>
{:catch error}
<!-- promise was rejected -->
<p>Something went wrong: {error.message}</p>
{/await}

revalidateなどが不要ならこれで十分

更新もシンプルなものなら
Promiseに再代入するだけでOK


仮想DOMが要らない

真なるリアクティブ

参考資料


最後に

  • SvelteはWeb開発に必要なものが最低限揃っている
    • Reactでよく使うユーティリティが標準実装
    • シンプルなLPなら追加の依存なしで作れそう
  • Svelte v5のRuneはReactに近い書き心地
    • 今までHookのような定義は少し癖があった
    • あらゆるフレームワークのいいとこどり
  • 学習コストはそんな高くない(ライフサイクルも素直)
  • Svelte kitはまだあまり触れていないが、
    仕組み自体はかなりシンプル