Локальное состояние

Локальное состояние в рамках библиотеки Atomico играет ключевую роль в управлении данными, которые привязаны к конкретному компоненту. Каждый компонент может иметь своё состояние, которое изменяется в ответ на события или действия пользователя, и это состояние влияет на отображаемую информацию. Atomico предоставляет эффективный и гибкий механизм для работы с таким состоянием.

Создание компонента с состоянием

Для работы с состоянием в Atomico используется хук useState, который позволяет создать переменную состояния и обновлять её при необходимости. Состояние компонента всегда привязано к нему, и любые изменения состояния автоматически приводят к перерисовке компонента.

Пример создания компонента с локальным состоянием:

import { html, useState } from 'atomico';

function Counter() {
  const [count, setCount] = useState(0);

  return html`
    <div>
      <p>Текущий счёт: ${count}</p>
      <button onCl ick=${() => setCount(count + 1)}>Увеличить</button>
      <button onCl ick=${() => setCount(count - 1)}>Уменьшить</button>
    </div>
  `;
}

В данном примере создаётся компонент Counter, который отображает текущий счёт и два кнопки для увеличения и уменьшения значения. useState(0) инициализирует состояние с начальным значением 0. Функция setCount обновляет это состояние при клике на кнопки.

Принцип работы useState

useState принимает начальное значение состояния как аргумент и возвращает массив из двух элементов: текущего значения состояния и функции для его обновления. Эта функция позволяет изменять состояние и инициировать повторный рендер компонента. После вызова функции обновления состояния Atomico автоматически перерисовывает компонент с новым значением.

Важно, что состояние компонента изолировано от других компонентов. Изменение состояния в одном компоненте не влияет на состояние других компонентов, что способствует чистоте архитектуры приложения.

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

Atomico позволяет работать с несколькими состояниями в одном компоненте. Для этого можно просто вызывать useState несколько раз, каждый раз создавая отдельную переменную состояния.

Пример:

import { html, useState } from 'atomico';

function Form() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  
  const handleSubmit = () => {
    console.log(`Имя: ${name}, Email: ${email}`);
  };

  return html`
    <form>
      <input
        type="text"
        value=${name}
        placeholder="Имя"
        onIn put=${(e) => setName(e.target.value)}
      />
      <input
        type="email"
        value=${email}
        placeholder="Email"
        onIn put=${(e) => setEmail(e.target.value)}
      />
      <button type="button" onCl ick=${handleSubmit}>Отправить</button>
    </form>
  `;
}

В этом примере используется два состояния: name и email. Каждый из них отслеживает данные для соответствующего поля формы. Это позволяет компоненту быть динамичным и легко управляемым.

Локальное состояние и производительность

Atomico использует виртуальный DOM для минимизации обновлений реального DOM, что делает работу с состоянием быстрым и эффективным. При изменении состояния только те части компонента, которые зависят от этого состояния, будут перерисованы. Это значительно сокращает количество операций с DOM и повышает производительность.

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

Мемоизация состояния

Иногда возникает необходимость хранить результаты вычислений, которые не изменяются при каждом рендере компонента. Для этого можно использовать хук useMemo. Он позволяет мемоизировать вычисления и возвращать значение, которое не будет пересчитываться, если входные данные не изменились.

Пример:

import { html, useState, useMemo } from 'atomico';

function ExpensiveComputation() {
  const [input, setInput] = useState(0);

  const expensiveResult = useMemo(() => {
    return input * 1000; // Сложная операция
  }, [input]);

  return html`
    <div>
      <input
        type="number"
        value=${input}
        onIn put=${(e) => setInput(Number(e.target.value))}
      />
      <p>Результат: ${expensiveResult}</p>
    </div>
  `;
}

В этом примере, несмотря на то что значение input изменяется часто, вычисление expensiveResult будет выполняться только в том случае, если input изменится. Это улучшает производительность.

Изменение состояния через событие

Чтобы эффективно обновлять состояние в ответ на события пользователя, Atomico поддерживает обработчики событий, которые можно связать с функциями обновления состояния. Типичные события — это клики, ввод текста, изменение формы и другие.

Пример использования обработчиков событий для обновления состояния:

import { html, useState } from 'atomico';

function Toggle() {
  const [isOn, setIsOn] = useState(false);

  const handleClick = () => {
    setIsOn(!isOn);
  };

  return html`
    <button onCl ick=${handleClick}>
      ${isOn ? 'Включено' : 'Выключено'}
    </button>
  `;
}

В этом примере состояние isOn меняется при каждом клике на кнопку, и текст кнопки изменяется в зависимости от состояния.

Передача состояния в дочерние компоненты

В Atomico компоненты могут передавать своё состояние дочерним компонентам через свойства (props). Это позволяет создавать сложные и динамичные структуры, где родительский компонент управляет состоянием, а дочерние компоненты могут использовать это состояние для своего отображения.

Пример:

import { html, useState } from 'atomico';

function Parent() {
  const [count, setCount] = useState(0);

  return html`
    <div>
      <button onCl ick=${() => setCount(count + 1)}>Увеличить</button>
      <Child count=${count} />
    </div>
  `;
}

function Child({ count }) {
  return html`<p>Текущее значение: ${count}</p>`;
}

Здесь компонент Parent управляет состоянием count, а дочерний компонент Child просто отображает его.

Работа с асинхронным состоянием

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

Пример:

import { html, useState, useEffect } from 'atomico';

function FetchData() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err);
        setLoading(false);
      });
  }, []);

  if (loading) return html`<p>Загрузка...</p>`;
  if (error) return html`<p>Ошибка: ${error.message}</p>`;
  return html`<pre>${JSON.stringify(data, null, 2)}</pre>`;
}

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

Заключение

Управление локальным состоянием в Atomico — это мощный инструмент для создания динамичных и интерактивных компонентов. Используя хуки, такие как useState, можно эффективно отслеживать изменения состояния, минимизируя количество обновлений DOM и улучшая производительность приложения. Atomico также позволяет удобно работать с несколькими состояниями, мемоизацией, обработчиками событий и асинхронными операциями, что делает его подходящим для создания современных веб-приложений.