Как использовать Svelte Keyed Each Block?

В этом посте мы узнаем, как использовать Svelte Keyed Each Block.

В обычном блоке Svelte Each Block мы используем ключевое слово each для вывода массива или списка. Хотя это отлично работает, когда у нас статические списки, возникает серьезная проблема, когда мы удаляем элементы из списка. Сначала мы рассмотрим эту проблему, а затем найдем ее решение.

1 — Проблема с каждым блоком

Чтобы продемонстрировать проблему, мы рассмотрим пример отображения книг и их соответствующих авторов.

Ниже представлен наш компонент App.

App.svelte

<script>
    import Book from "./Book.svelte"

    let books = [{
        bookName: "Eye of the World",
    },
    {
        bookName: "The Way of Kings",
    },
    {
        bookName: "The Name of the Wind",
    }]

    function handleClick() {
        books = books.slice(1);
    }

</script>

<h1>Welcome to the Fantasy Library</h1>
{#each books as book, idx}
<h3>{idx + 1}</h3>
<Book 
    bookName = {book.bookName}
/>
{/each}
<button on:click={handleClick}>
    Remove first Book
</button>
Вход в полноэкранный режим Выйти из полноэкранного режима

В приведенном выше фрагменте кода у нас есть массив books с тремя жестко закодированными книгами. Мы используем блок each для рендеринга books с помощью компонента Book. Наконец, у нас есть кнопка для удаления первой книги из блока each. Когда пользователь нажимает на кнопку, мы вызываем функцию handleClick(), которая разрезает массив books.

Ниже приведен код компонента Book.

Book.svelte

<script>
    const authors = {
        "Eye of the World": "Robert Jordan",
        "The Way of Kings": "Brandon Sanderson",
        "The Name of the Wind": "Patrick Rothfuss",
    }

    export let bookName;

    const author = authors[bookName];
</script>
<div>
    <span>Book Name: {bookName} // Author: {author}</span>
</div>
Вход в полноэкранный режим Выйти из полноэкранного режима

В этом компоненте у нас есть карта от книги к автору. На основе ввода bookName мы определяем имя автора.

Если мы запустим приложение сейчас, а затем один раз нажмем кнопку для удаления первой книги, то увидим следующий результат.

Как вы можете видеть, bookName и authorName не совпадают. Хотя первая книга была удалена правильно, authorName перепуталось.

Почему это происходит?

Причина в том, что когда мы изменяем базовый массив блока each, Svelte добавляет и удаляет элементы из конца блока. Он также обновляет все значения, которые изменились. Это поведение по умолчанию.

В результате последний элемент удаляется, а элементы над ним обновляются. Однако значение author не обновляется, поскольку оно является локальной константой компонента Book. Его значение было зафиксировано во время инициализации компонента. Это приводит к несоответствию данных.

2 — Блок Svelte Keyed Each.

Чтобы обойти эту проблему, нам нужно использовать блок keyed each.

Смотрите пример ниже:

App.svelte.

<script>
    import Book from "./Book.svelte"

    let books = [{
        id: 1,
        bookName: "Eye of the World",
    },
    {
        id: 2,
        bookName: "The Way of Kings",
    },
    {
        id: 3,
        bookName: "The Name of the Wind",
    }]

    function handleClick() {
    books = books.slice(1);
    }

</script>

<h1>Welcome to the Fantasy Library</h1>
{#each books as book, idx (book.id)}
<h3>{idx + 1}</h3>
<Book 
    bookName = {book.bookName}
/>
{/each}
<button on:click={handleClick}>
    Remove first Book
</button>
Вход в полноэкранный режим Выйти из полноэкранного режима

По сути, здесь мы вводим поле id в массив books. Каждая книга имеет уникальный идентификатор. В реальном приложении этот id может быть также идентификатором базы данных. Суть в том, что он должен быть уникальным для каждого элемента.

Мы также используем этот id в блоке each, как показано ниже.

{#each books as book, idx (book.id)}
Вход в полноэкранный режим Выход из полноэкранного режима

По сути, роль этого поля id заключается в том, чтобы помочь Svelte определить, какой узел DOM должен быть изменен при обновлении блока each. После этой модификации, если мы запустим приложение и нажмем на кнопку, мы увидим правильные данные, как показано ниже.

Название книги и имя автора совпадают, как и ожидалось. Первая книга была успешно удалена. Однако Svelte удалил только соответствующий узел DOM, а другие узлы остались такими, какими они были до обновления.

Заключение

Таким образом, мы научились использовать Svelte Keyed Each Block. Это очень полезно, когда нам требуется обновлять элементы внутри каждого блока.

Надеюсь, этот небольшой пост был полезен. Если у вас есть какие-либо комментарии или вопросы по этой статье, пожалуйста, напишите их в разделе комментариев ниже.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *