Skip to content

{#with ...} block #6951

@accuser

Description

@accuser

Describe the problem

Objects with many fields or longer names can cause markup to become noisy. Consider this journalArticle prop:

  <script lang="ts">
    export let journalArticle: {
      abstract: string;
      authors: string;
      journal: string;
      linkTitle: string;
      publishedAt: string;
      slug: string;
      title: string;
    };
  </script>

when rendering:

    <h1>{journalArticle.title}</h1>
    <p>{journalArticle.authors}</p>
    <p>{journalArticle.abstract}</p>
    <p>Published {journalArticle.publishedAt} in {journalArticle.journal}</p>

The journalArticle prop is referred to five times in the simple example above, and whilst each reference is important, adds little to the clarity of the markup.

Describe the proposed solution

The {#each ...} block introduces a mechanism to iterate over an array of elements and deconstruct each:

  <ul>
    {#each journalArticles as {slug, linkTitle}}
      <li>
        <a href={slug}>{linkTitle}</a>
      </li>
    {/each}
  </ul>

A similar approach could be adopted for single objects, deconstructing the object for the scope of the block. Consider the example above in a new #with block:

  {#with journalArticle as {abstract, authors, journal, title}}
    <h1>{title}</h1>
    <p>{authors}</p>
    <p>{abstract}</p>
    <p>Published {publishedAt} in {journal}</p>
  {/with}

The deconstructed fields are local to the block, and are deconstructed because they are used in the block.

#with could also be used with arrays:

  {#with journalArticles as [featuredArticle, ...rest]}
    {#with featuredArticle as {abstract, authors, journal, title}}
      <h1>{title}</h1>
      <p>{authors}</p>
      <p>{abstract}</p>
      <p>Published {publishedAt} in {journal}</p>
    {/with}
    <ul>
      {#each rest as {slug, linkTitle}}
      <li>
        <a href={slug}>{linkTitle}</a>
      </li>
    {/each}
  {/with}

Alternatives considered

It is obviously possible to deconstruct a prop (or other object) in the component script:

  <script lang="ts">
    export let journalArticle: {
      abstract: string;
      authors: string;
      journal: string;
      linkTitle: string;
      publishedAt: string;
      slug: string;
      title: string;
    };

  const { abstract, authors, journal, linkTitle, publishedAt, slug, title } = journalArticle;

However, this exposes all deconstructed fields to the whole component. A local, block-scoped deconstruction using a #with block is more purposeful.

Importance

would make my life easier

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions