Концепция реактивных переменных

Одной из основных особенностей Svelte является реактивность. Это концепция, при которой изменения данных автоматически отражаются в интерфейсе, без необходимости вручную обновлять DOM или использовать сторонние библиотеки для управления состоянием. В Svelte реактивность встроена на уровне языка, что упрощает разработку и повышает производительность.

Основы реактивности в Svelte

Reaktivность в Svelte достигается через реактивные переменные. Эти переменные отслеживают изменения данных и автоматически обновляют связанные с ними части интерфейса. Пример базового использования:

<script>
  let count = 0;
</script>

<button on:click={() => count += 1}>
  Счётчик: {count}
</button>

В этом примере переменная count является реактивной. Когда пользователь нажимает на кнопку, значение переменной изменяется, и Svelte автоматически обновляет DOM, отображая новое значение счётчика.

Реактивность через декларацию

Svelte использует декларативный подход для описания реактивности. Чтобы указать, что переменная или выражение должно быть реактивным, достаточно использовать конструкцию $:, которая помечает реактивное выражение. Пример:

<script>
  let x = 5;
  let y = 10;
  
  $: sum = x + y;
</script>

<p>Сумма: {sum}</p>

Здесь переменная sum автоматически пересчитывается каждый раз, когда изменяются значения x или y. Оператор $: указывает, что выражение справа должно быть реактивным, и при изменении значений переменных Svelte автоматически пересчитает sum и обновит DOM.

Комплексная реактивность

Реактивные выражения могут быть не только простыми арифметическими операциями. В Svelte можно использовать более сложные вычисления и выражения, которые автоматически обновляются при изменении зависимых переменных. Это позволяет легко строить динамические интерфейсы.

<script>
  let firstName = "Иван";
  let lastName = "Иванов";
  
  $: fullName = `${firstName} ${lastName}`;
</script>

<p>Полное имя: {fullName}</p>

В данном примере fullName будет автоматически обновляться при изменении firstName или lastName. Этот подход позволяет минимизировать необходимость в дополнительных методах или событиях для отслеживания изменений.

Использование реактивных переменных в методах

Реактивность в Svelte может быть использована не только в простых выражениях, но и в более сложных методах. Например, при взаимодействии с API, загрузке данных или фильтрации:

<script>
  let searchTerm = '';
  let items = ['Яблоки', 'Бананы', 'Груши', 'Апельсины'];
  
  $: filteredItems = items.filter(item => item.includes(searchTerm));
</script>

<input type="text" bind:value={searchTerm} placeholder="Поиск...">
<ul>
  {#each filteredItems as item}
    <li>{item}</li>
  {/each}
</ul>

Здесь, при каждом изменении значения searchTerm, Svelte автоматически обновит список filteredItems, отфильтровав элементы на основе введённого текста.

Реактивность с использованием store

Для более сложных приложений в Svelte часто используется концепция store (хранилища). Store позволяет управлять состоянием, которое может быть доступно и изменяемо из разных частей приложения. В Svelte есть несколько типов store, включая writable, readable и derived.

Пример использования writable store:

<script>
  import { writable } from 'svelte/store';
  
  const count = writable(0);
</script>

<button on:click={() => $count += 1}>
  Счётчик: {$count}
</button>

Здесь переменная count хранится в хранилище типа writable. Хранилища могут быть реактивными, и, используя $ перед названием store, можно автоматически отслеживать изменения и обновлять интерфейс.

Оптимизация с реактивными переменными

Svelte автоматически оптимизирует обновления при использовании реактивных переменных. В случае, если несколько реактивных переменных зависят друг от друга, Svelte старается минимизировать количество перерисовок интерфейса, обновляя только те части DOM, которые действительно изменились.

Кроме того, Svelte использует компиляцию для создания эффективного кода, который минимизирует лишние вычисления и обновления. Например, если переменная, которая не используется в шаблоне, изменяется, её обновление не вызовет перерасчёта DOM.

Пример: реактивность и асинхронные данные

При работе с асинхронными данными важно учитывать, что Svelte будет корректно работать с реактивными переменными даже в случае загрузки данных с сервера. Пример:

<script>
  let data = [];
  let loading = true;
  
  async function fetchData() {
    const response = await fetch('https://api.example.com/data');
    data = await response.json();
    loading = false;
  }
  
  fetchData();
</script>

{#if loading}
  <p>Загрузка...</p>
{:else}
  <ul>
    {#each data as item}
      <li>{item.name}</li>
    {/each}
  </ul>
{/if}

Здесь при изменении состояния переменной data или loading Svelte автоматически обновит DOM, отображая либо индикатор загрузки, либо саму информацию.

Референсное поведение реактивных переменных

С момента появления реактивных переменных в Svelte разработчики столкнулись с понятием “референсного типа данных”. Важно понимать, что при изменении сложных объектов, таких как массивы или объекты, Svelte отслеживает изменения на уровне ссылки, а не содержимого объекта. Чтобы гарантировать реактивность при изменении содержимого, рекомендуется использовать методы, которые изменяют саму ссылку, например, с помощью splice для массивов.

<script>
  let items = ['Яблоки', 'Бананы'];
  
  function addItem() {
    items = [...items, 'Груши']; // Создаём новый массив
  }
</script>

<button on:click={addItem}>Добавить элемент</button>
<ul>
  {#each items as item}
    <li>{item}</li>
  {/each}
</ul>

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

Заключение

Реактивность является ключевой особенностью Svelte и позволяет разработчикам легко управлять состоянием и обновлять интерфейс при изменении данных. С помощью реактивных переменных, реактивных выражений и store Svelte упрощает создание динамичных, эффективных приложений, минимизируя код, необходимый для обновления DOM.