7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React開発者のためのSvelte 5入門講座 第一章

Last updated at Posted at 2024-08-13

Introduction

こんにちわ、milkyskiesだよ♪
Svelte 5の講座を始めるよ♪
React厨の皆様ならば1時間で覚えられるね♪

使われる技術

React

  • NextJS (App Router)
  • TypeScript
  • Tailwind CSS

Svelte 5

  • SvelteKit
  • TypeScript
  • Tailwind CSS

State

Stateの基本

React Svelte 5
useState $state

React

src/app/page.tsx
import React, { useState } from "react";

export default function Page() {
    const [name, setName] = useState("太郎");

    return (
        <p>
            こんにちは、{name}</p>
    );
}

Svelte 5

src/routes/+page.svelte
<script lang="ts">
    let name = $state("太郎");
</script>

<p>
    こんにちは、 {name}</p>

Stateの変更

ついでにuseEffectのSvelte 5版も紹介するよ!

React Svelte 5
setName("次郎") name = "次郎"
useEffect $effect

React

src/app/page.tsx
import React, { useState, useEffect } from "react";

export default function Page() {
    const [name, setName] = useState("太郎");

    useEffect(() => {
        setName("次郎");
    }, []);

    return (
        <p>
            こんにちは、{name}</p>
    );
}

Svelte 5

src/routes/+page.svelte
<script lang="ts">
    let name = $state("太郎");

    $effect(() => {
        name = "次郎";
    });
</script>

<p>
    こんにちは、 {name}</p>

ボタンでstateを変更

SvelteではonClickじゃなくてonclickだよ!本来のHTMLと一緒だよ!

React Svelte 5
onClick onclick

React

src/app/page.tsx
import React, { useState, useEffect } from "react";

export default function Page() {
    const [count, setCount] = useState(0);

    function increaseCount(amount: number) {
        setCount((count) => count + amount);
    }

    return (
        <>
            <p>count: {count}</p>
            <button onClick={() => increaseCount(1)}>countを増やす</button>
        </>
    );
}

Svelte 5

src/routes/+page.svelte
<script lang="ts">
    let count = $state(0);

    function increaseCount(amount: number) {
        count += amount;
    }
</script>

<p>count: {count}</p>
<button onclick={() => increaseCount(1)}>countを増やす</button>

入力欄でリアルタイムでstateを更新

ここに関しては、ReactとSvelteがかなり違ってくる。
個人的にはSvelteのほうが圧倒的に書きやすいと思う。

React Svelte 5
onChange bind

React

src/app/page.tsx
import React, { ChangeEvent, useState } from "react";

export default function Page() {
  const [name, setName] = useState("");

  function handleInputChange(event: ChangeEvent<HTMLInputElement>) {
      setName(event.target.value);
  }

  return (
      <>
          <input onChange={handleInputChange}>
          <p>こんにちは、{name}</p>
      </>
  );
}

Svelte 5

src/routes/+page.svelte
<script lang="ts">
    let name = $state("");
</script>

<input bind:value={name}>
<p>こんにちは、{name}</p>

Components

Componentの作成

ついでにTailwindの使い方も少し紹介するよ!

React Svelte 5
className class

別ファイルでcomponentを作成する方法

React

src/components/card.tsx
type CardProps = {
    title: string
    text: string
};

export function Card({ title, text }: CardProps) {
  return (
    <div className="bg-slate-200 h-screen w-screen flex items-center justify-center">
        <div className="bg-white shadow-2xl rounded-lg w-96 min-h-32 p-4">
            <h2 className="text-2xl font-bold">{title}</h2>
            <p className="text-slate-500 mt-2">{text}</p>
        </div>
    </div>
  );
}
src/app/page.tsx
import { Card } from '@/components/card';

export default function Page() {
  return (
    <Card title="カード" text="こんにちは!" />
  );
}

Svelte 5

src/components/card.svelte
<script lang="ts">
    type CardProps = {
		title: string
		text: string
	};

	let { title, text }: CardProps = $props();
</script>

<div class="bg-slate-200 h-screen w-screen flex items-center justify-center">
    <div class="bg-white shadow-2xl rounded-lg w-96 min-h-32 p-4">
        <h2 class="text-2xl font-bold">{title}</h2>
        <p class="text-slate-500 mt-2">{text}</p>
    </div>
</div>
src/routes/+page.svelte
<script lang="ts">
    import Card from '@components/card.svelte';
</script>

<Card title="カード" text="こんにちは!" />

同じファイルでcomponentを作る方法

React

src/app/page.tsx
type CardProps = {
    title: string
    text: string
};

function Card({ title, text }: CardProps) {
  return (
    <div className="bg-slate-200 h-screen w-screen flex items-center justify-center">
        <div className="bg-white shadow-2xl rounded-lg w-96 min-h-32 p-4">
            <h2 className="text-2xl font-bold">{title}</h2>
            <p className="text-slate-500 mt-2">{text}</p>
        </div>
    </div>
  );
}

export default function Page() {
  return (
    <Card title="カード" text="こんにちは!" />
  );
}

Svelte 5

こっちはあまりおすすめしないかも!Componentを作るときはだいたい上記みたいに別ファイルで作りましょう

src/routes/+page.svelte
<script lang="ts">
	type CardProps = {
		title: string;
		text: string;
	};
</script>

{#snippet card({ title, text }: CardProps)}
	<div class="bg-slate-200 h-screen w-screen flex items-center justify-center">
		<div class="bg-white shadow-2xl rounded-lg w-96 min-h-32 p-4">
			<h2 class="text-2xl font-bold">{title}</h2>
			<p class="text-slate-500 mt-2">{text}</p>
		</div>
	</div>
{/snippet}

<div class="bg-slate-2000 h-screen w-screen flex items-center justify-center">
	{@render card({ title: 'カード', text: 'こんにちは!' })}
</div>

現時点(2024-08-13)、Svelte 5のコードブロックはまだQiitaに完全対応されていないようなので、コードブロックにエラーが出ていますが、コード自体は大丈夫です。


Componentにcomponentを渡す方法

Reactと同じく、一つの引数をchildrenと名付けるとcomponentの中にcomponentを入れられるようになる!
childrenじゃなくてもいいけど、Reactと同じくその場合は他のpropと同じように渡さないといけなくなるから注意!

React Svelte 5
ReactNode Snippet

React

src/components/card.tsx
import { ReactNode } from 'react';

type CardProps = {
    title: string
    children: ReactNode
};

export function Card({ title, children }: CardProps) {
  return (
    <div className="bg-slate-200 h-screen w-screen flex items-center justify-center">
        <div className="bg-white shadow-2xl rounded-lg w-96 min-h-32 p-4">
            <h2 className="text-2xl font-bold">{title}</h2>
            <div className="text-slate-500 mt-2">
              {children}
            </div>
        </div>
    </div>
  );
}
src/app/page.tsx
import { Card } from '@/components/card';

export default function Page() {
  return (
    <Card title="カード">
        <p>こんにちは!</p>
    </Card>
  );
}

Svelte 5

src/components/card.svelte
<script lang="ts">
	import type { Snippet } from 'svelte';

	type CardProps = {
		title: string;
		children: Snippet;
	};

	let { title, children }: CardProps = $props();
</script>

<div class="bg-slate-200 h-screen w-screen flex items-center justify-center">
	<div class="bg-white shadow-2xl rounded-lg w-96 min-h-32 p-4">
		<h2 class="text-2xl font-bold">{title}</h2>
		<p class="text-slate-500 mt-2">
			{@render children()}
		</p>
	</div>
</div>
src/routes/+page.svelte
<script lang="ts">
    import Card from '@components/card.svelte';
</script>

<Card title="カード">
    <p>こんにちは!</p>
</Card>

HTMLElementを継承してComponentを作る方法

React

src/components/button.tsx
import { ButtonHTMLAttributes } from 'react';

type ButtonProps = {
  label: string;
  className?: string;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;

export const Button = ({ label, className, ...restProps }: ButtonProps) => {
  return (
    <button type="button" className={`bg-blue-500 text-white px-4 py-2 rounded-md ${className}`} {...restProps}>
      {label}
    </button>
  );
};

Svelte 5

src/components/button.svelte
<script lang="ts">
	import type { HTMLButtonAttributes } from 'svelte/elements';

	type ButtonProps = {
		label: string;
		class?: string;
	} & HTMLButtonAttributes;

	let { label, class: className, ...restProps }: ButtonProps = $props();
</script>

<button class={`bg-blue-500 text-white px-4 py-2 rounded-md ${className}`} {...restProps}>
	{label}
</button>

現時点(2024-08-13)、Svelte 5のコードブロックはまだQiitaに完全に対応されていないようなので、コードブロックにエラーが出ていますが、コード自体は大丈夫です。

まとめ

いかがでしたか!Svelte 5はSvelte 4と比較すると、よりReactっぽい書き方になっている感じするね!

次回は、Svelteの条件分岐やループなどの紹介もしていきたいと思います。

ほな!

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?