Svelteの {#each} を使いこなす!ループ処理と動的リストの基本解説
大平 恵美
大平 恵美
2025-02-06
Svelteの {#each} 構文を使えば、配列データを簡単にループ処理し、動的なリストを作成できます。本記事では、{#each} の基本構文から実践的な使い方、key を指定した最適化方法まで詳しく解説します。コード例を交えながら、効率的なリスト表示の方法を学びましょう。
あなた:

あなたはプロのフロントエンドエンジニアです。 each構文の仕組みについて教えてください。

<div class="grid grid-cols-1 md:grid-cols-3 gap-4 w-11/12">
                    {#each [
                        {
                          title: "SvelteKitで学ぶ!ButtonコンポーネントとPropsの基本理解ガイド",
                          description: "本記事では、SvelteKitで再利用可能なButtonコンポーネントを作成する方法と、Props(プロパティ)を使ったデータの受け渡しについて解説します。export letによるデフォルト値の設定、親コンポーネントでの上書き方法、target属性の管理まで、実践的なコード例とともに詳しく紹介。初心者でも分かりやすく、効率的な開発に役立つ内容をお届けします。",
                          imageUrl: "https://example.com/image.jpg",
                          link: "/blog/sveltekit-button-props",
                          tags: ["SvelteKit", "Buttonコンポーネント", "Props", "export let", "デフォルト値" ,"再利用可能", "データバインディング", "親コンポーネント", "属性管理", "UI開発"],
                          likes: 10,
                          author: {
                            name: "大平恵美",
                            avatar: "https://example.com/avatar.jpg",
                            profileLink: "/user/ohiramegumi",
                            date: "2025年2月5日",
                            time: "13:14",
                          }
                        },
                        {
                          title: "SvelteKitで学ぶ!ButtonコンポーネントとPropsの基本理解ガイド",
                          description: "本記事では、SvelteKitで再利用可能なButtonコンポーネントを作成する方法と、Props(プロパティ)を使ったデータの受け渡しについて解説します。export letによるデフォルト値の設定、親コンポーネントでの上書き方法、target属性の管理まで、実践的なコード例とともに詳しく紹介。初心者でも分かりやすく、効率的な開発に役立つ内容をお届けします。",
                          imageUrl: "https://example.com/image.jpg",
                          link: "/blog/sveltekit-button-props",
                          tags: ["SvelteKit", "Buttonコンポーネント", "Props", "export let", "デフォルト値" ,"再利用可能", "データバインディング", "親コンポーネント", "属性管理", "UI開発"],
                          likes: 10,
                          author: {
                            name: "大平恵美",
                            avatar: "https://example.com/avatar.jpg",
                            profileLink: "/user/ohiramegumi",
                            date: "2025年2月5日",
                             time: "13:14",
                          }
                        },
                      ] as post}
                        <BlogCard 
                          title={post.title}
                          description={post.description}
                          imageUrl={post.imageUrl}
                          link={post.link}
                          tags={post.tags}
                          likes={post.likes}
                          author={post.author}
                        />
                      {/each}
                </div>
ChatGPT:

Svelteの {#each} 構文は、配列の要素をループしてコンポーネントや要素を動的に生成するための仕組みです。あなたのコードは基本的には正しく動作するはずですが、少し整理して {#each} の仕組みと最適な書き方について説明します。


{#each} の基本構文

Svelteの {#each} 構文は、JavaScriptの forEachmap に似た仕組みを持っています。

{#each 配列 as 変数}
  <!-- 繰り返す内容 -->
{/each}

たとえば、次のようにリストをレンダリングできます。

<script>
  let items = ['Apple', 'Banana', 'Cherry'];
</script>

<ul>
  {#each items as item}
    <li>{item}</li>
  {/each}
</ul>

この場合、 <li>Apple</li><li>Banana</li><li>Cherry</li> が順番に生成されます。


あなたのコードの {#each} 分解

あなたのコードでは、ブログ記事のデータを直接 each でループし、それぞれの postBlogCard コンポーネントとしてレンダリングしています。

現在のコード

{#each [
  { title: "...", description: "...", imageUrl: "...", link: "...", tags: [...], likes: 10, author: {...} },
  { title: "...", description: "...", imageUrl: "...", link: "...", tags: [...], likes: 10, author: {...} }
] as post}
  <BlogCard 
    title={post.title}
    description={post.description}
    imageUrl={post.imageUrl}
    link={post.link}
    tags={post.tags}
    likes={post.likes}
    author={post.author}
  />
{/each}

改善ポイント

  1. データを <script> 内で定義する

    • 配列データを直接 {#each} 内に書くのは避け、 <script> に分けたほうが可読性が向上し、保守性も上がります。
  2. 一意な key を指定する

    • each のループでアイテムをレンダリングする際は、識別可能な key を指定するとパフォーマンスが向上します(DOMの変更を最小限に抑えられる)。
    • 例えば、 title が一意なら key にできます。

修正後のコード

<script>
  let posts = [
    {
      title: "SvelteKitで学ぶ!ButtonコンポーネントとPropsの基本理解ガイド",
      description: "本記事では、SvelteKitで再利用可能なButtonコンポーネントを作成する方法と、Props(プロパティ)を使ったデータの受け渡しについて解説します。",
      imageUrl: "https://example.com/image.jpg",
      link: "/blog/sveltekit-button-props",
      tags: ["SvelteKit", "Buttonコンポーネント", "Props", "export let", "デフォルト値"],
      likes: 10,
      author: {
        name: "大平恵美",
        avatar: "https://example.com/avatar.jpg",
        profileLink: "/user/ohiramegumi",
        date: "2025年2月5日",
        time: "13:14",
      }
    },
    {
      title: "SvelteKitで学ぶ!Propsの受け渡しと再利用可能なコンポーネント設計",
      description: "SvelteKitでのPropsの使い方を学び、効率的にコンポーネントを作る方法を解説。",
      imageUrl: "https://example.com/image2.jpg",
      link: "/blog/sveltekit-props",
      tags: ["Svelte", "Props", "コンポーネント設計"],
      likes: 25,
      author: {
        name: "佐藤太郎",
        avatar: "https://example.com/avatar2.jpg",
        profileLink: "/user/satotaro",
        date: "2025年2月6日",
        time: "14:30",
      }
    }
  ];
</script>

<div class="grid grid-cols-1 md:grid-cols-3 gap-4 w-11/12">
  {#each posts as post (post.title)}
    <BlogCard 
      title={post.title}
      description={post.description}
      imageUrl={post.imageUrl}
      link={post.link}
      tags={post.tags}
      likes={post.likes}
      author={post.author}
    />
  {/each}
</div>

修正のポイント

  1. データを <script> に分離

    • ループの中に直接オブジェクトを書かず、 posts 配列として定義。
    • これにより、データの管理がしやすくなり、コンポーネントの再利用性も向上。
  2. key を追加

    • {#each posts as post (post.title)}(post.title) 部分は、Svelteに「この title が一意な識別子だよ」と教えるためのもの。
    • これがあると、リストの要素が変更されたときに、不要な再レンダリングを防げる。

まとめ

{#each 配列 as 変数 (key)} の形でループを使う。
✅ データは <script> で定義し、テンプレートから分離する。
key を指定してパフォーマンス最適化する。

このように整理すると、より理解しやすく、実践的なコードになります!

あなた:

初めのlet postは代入宣言のようなものですか。

ChatGPT:

はい、そのとおりです!

let posts = [...] の部分は、JavaScript(およびSvelte)での 変数の宣言と代入 です。 let は「この変数は後で変更できる(再代入可能)」という意味を持つキーワードで、 posts に配列データを代入しています。


let posts = [...] の解説

<script>
  let posts = [
    {
      title: "SvelteKitで学ぶ!ButtonコンポーネントとPropsの基本理解ガイド",
      description: "本記事では、SvelteKitで再利用可能なButtonコンポーネントを作成する方法と、Props(プロパティ)を使ったデータの受け渡しについて解説します。",
      imageUrl: "https://example.com/image.jpg",
      link: "/blog/sveltekit-button-props",
      tags: ["SvelteKit", "Buttonコンポーネント", "Props"],
      likes: 10,
      author: {
        name: "大平恵美",
        avatar: "https://example.com/avatar.jpg",
        profileLink: "/user/ohiramegumi",
        date: "2025年2月5日",
        time: "13:14",
      }
    }
  ];
</script>
  • let posts = [...] は「配列データを変数 posts に格納する処理」

    • これで posts は、ブログ記事のデータを持つ「配列」として定義される。
    • 配列の中にはオブジェクト({} で囲まれたデータ)が入っている。
  • let を使っている理由

    • let を使うことで、後から posts を更新できる(例:APIからデータを取得して更新)。
    • const にすると、変数の再代入ができないため、動的に変更する場合は let を使うのが適切。

「代入」と「宣言」の違い

  1. 宣言 (Declaration)

    • 変数を定義すること。
    • 例: let posts; → 変数 posts を定義するが、値はまだセットしない。
  2. 代入 (Assignment)

    • 変数に値をセットすること。
    • 例: posts = [...]posts にデータ(配列)を代入する。
  3. 宣言と代入を同時に行う

    • 例: let posts = [...];
    • let posts で変数を宣言し、すぐに配列を代入している。

{#each posts as post} での post について

{#each posts as post}
  <BlogCard title={post.title} />
{/each}
  • posts の配列の中には複数のオブジェクトが入っている。
  • each 文では、 posts の各要素(オブジェクト)を post という一時的な変数に代入しながらループを回す。
  • つまり、 {#each posts as post}forEach に近い動作をする。

イメージ

posts.forEach(post => {
  console.log(post.title); // 各postのtitleを出力
});

結論

let posts = [...]「配列データを変数 posts に代入する処理」 である。
let を使うことで、後から posts を更新することが可能。
{#each posts as post}posts の各要素を post に代入しながらループを回す

こんな感じでOKですか? 😊

あなた:

例えば、

<BlogCard title={post.title} />

これはlet postsの中で指定したtitleを探して出力してください、という意味ですか。

ChatGPT:

はい、その理解で合っています! 🎯

このコード:

<BlogCard title={post.title} />

posttitleBlogCard コンポーネントの title プロパティ(Props)として渡す」 という意味です。


もう少し詳しく解説

  1. {#each posts as post}post に代入

    {#each posts as post}
    
    • posts は配列なので、 {#each} を使うと、 posts の各要素(オブジェクト)を post という変数に一時的に代入しながらループを回します。
  2. post.titleBlogCard に渡す

    <BlogCard title={post.title} />
    
    • post.title は、 post に代入されたオブジェクトの title の値を取得します。
    • その値を BlogCardtitle プロパティとして渡します。

具体例で理解する

もし posts が次のようなデータだった場合:

<script>
  let posts = [
    {
      title: "SvelteKit入門",
      description: "SvelteKitの基本を学ぶ記事です。",
    },
    {
      title: "Propsの使い方",
      description: "SvelteのPropsの仕組みを解説します。",
    }
  ];
</script>

すると {#each} のループが次のように展開されます:

<BlogCard title="SvelteKit入門" />
<BlogCard title="Propsの使い方" />

これは posts の各 titleBlogCardtitle に設定して表示する」 という意味になります。


ポイントまとめ

{#each posts as post}posts の各オブジェクトを post に代入しながらループする。
post.titleposts の各オブジェクトの title を取得する。
✅ 取得した titleBlogCardtitle に渡す(Propsとして)。

この流れでバッチリです! 🎉

あなた:

上記のコードを{#each}を使って書いてみてください。

ChatGPT:

はい! {#each} を使って上記のコードを書き換えると、次のようになります。


【元のコード(ループなし)】

<BlogCard title="SvelteKit入門" />
<BlogCard title="Propsの使い方" />

このコードは 2つの BlogCard を手動で書いている 状態ですね。


{#each} を使ったコード】

<script>
  let posts = [
    {
      title: "SvelteKit入門",
      description: "SvelteKitの基本を学ぶ記事です。",
    },
    {
      title: "Propsの使い方",
      description: "SvelteのPropsの仕組みを解説します。",
    }
  ];
</script>

{#each posts as post}
  <BlogCard title={post.title} />
{/each}

【コードの解説】

  1. posts 配列を用意する

    <script>
      let posts = [
        { title: "SvelteKit入門", description: "SvelteKitの基本を学ぶ記事です。" },
        { title: "Propsの使い方", description: "SvelteのPropsの仕組みを解説します。" }
      ];
    </script>
    
    • 配列の中にオブジェクトを用意し、それぞれの title を保持。
  2. {#each} でループを回す

    {#each posts as post}
      <BlogCard title={post.title} />
    {/each}
    
    • posts の配列の各要素を post という変数に入れて、ループを回す。
    • post.titleBlogCardtitle プロパティ(Props)に渡す。

【ループ展開後のイメージ】

上記の {#each} を使ったコードは、最終的にはこのように展開される ことになります。

<BlogCard title="SvelteKit入門" />
<BlogCard title="Propsの使い方" />

手動で書いていたコードと同じ結果 になります! 🎉


【補足:key を追加するとより良い】

もし posts の内容が変わる可能性がある場合(動的に追加・削除されるなど)、 key を指定すると パフォーマンスが向上 します。

{#each posts as post (post.title)}
  <BlogCard title={post.title} />
{/each}
  • post.titlekey に指定すると、Svelteは title を識別して 必要な部分だけ更新 してくれる。

これで {#each} を使って動的に BlogCard をレンダリングできます!
この書き方をマスターすると、リストを扱うときにすごく便利ですよ! 😊🚀