createResource: асинхронная загрузка данных

createResource — это ключевая функция в Solid.js, предназначенная для работы с асинхронными данными. Она позволяет эффективно загружать данные в компоненте, управляя состоянием загрузки, ошибками и результатами. В отличие от стандартных React хуков, таких как useEffect и useState, createResource построена с учетом реактивности и оптимизирована для производительности, что делает её отличным инструментом для работы с асинхронными запросами в Solid.js.

Основы работы с createResource

Функция createResource принимает два аргумента:

  1. Функция для получения данных — это асинхронная функция, которая возвращает промис.
  2. Значение (опционально) — начальное значение ресурса. Это значение используется, когда асинхронная функция ещё не выполнилась, например, при первой загрузке компонента.
import { createResource } from "solid-js";

const fetchData = async () => {
  const response = await fetch("https://api.example.com/data");
  return await response.json();
};

const MyComponent = () => {
  const [data] = createResource(fetchData);

  return (
    <div>
      {data.loading && <p>Загрузка...</p>}
      {data.error && <p>Ошибка загрузки</p>}
      {data() && <pre>{JSON.stringify(data(), null, 2)}</pre>}
    </div>
  );
};

В этом примере createResource используется для загрузки данных с внешнего API. Ресурс автоматически отслеживает состояния загрузки (loading), ошибки (error) и результата (data). Эти состояния можно использовать для отображения различных вариантов интерфейса в зависимости от состояния загрузки данных.

Состояния ресурса

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

  • loading — логическое значение, которое указывает, что данные всё ещё загружаются.
  • error — если запрос завершился с ошибкой, это свойство содержит объект ошибки.
  • data — результат выполнения асинхронной функции, если она успешно завершена.

Также важно отметить, что доступ к данным осуществляется через функцию data(). Это связано с тем, что Solid.js использует систему реактивных данных, и data() будет пересчитываться при изменении состояния.

Использование зависимостей в createResource

Если асинхронная загрузка зависит от внешних параметров или состояния компонента, можно передать зависимости в createResource. Для этого можно использовать вторым аргументом массив зависимостей, аналогичный тому, как это работает в useEffect в React. Таким образом, если значение зависимостей изменится, будет повторно выполнен асинхронный запрос.

import { createResource } from "solid-js";

const fetchData = async (id) => {
  const response = await fetch(`https://api.example.com/data/${id}`);
  return await response.json();
};

const MyComponent = () => {
  const [id, setId] = createSignal(1);
  const [data] = createResource(id, fetchData);

  return (
    <div>
      <button onCl ick={() => setId(id() + 1)}>Загрузить следующее</button>
      {data.loading && <p>Загрузка...</p>}
      {data.error && <p>Ошибка загрузки</p>}
      {data() && <pre>{JSON.stringify(data(), null, 2)}</pre>}
    </div>
  );
};

В этом примере асинхронная функция fetchData зависит от параметра id, который можно изменять с помощью setId. Каждый раз, когда id изменяется, Solid.js автоматически повторно выполняет запрос для нового id.

Использование createResource с множественными запросами

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

import { createResource } from "solid-js";

const fetchData1 = async () => {
  const response = await fetch("https://api.example.com/data1");
  return await response.json();
};

const fetchData2 = async () => {
  const response = await fetch("https://api.example.com/data2");
  return await response.json();
};

const MyComponent = () => {
  const [data1] = createResource(fetchData1);
  const [data2] = createResource(fetchData2);

  return (
    <div>
      {data1.loading && <p>Загрузка данных 1...</p>}
      {data1.error && <p>Ошибка загрузки данных 1</p>}
      {data1() && <pre>{JSON.stringify(data1(), null, 2)}</pre>}

      {data2.loading && <p>Загрузка данных 2...</p>}
      {data2.error && <p>Ошибка загрузки данных 2</p>}
      {data2() && <pre>{JSON.stringify(data2(), null, 2)}</pre>}
    </div>
  );
};

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

Обработка ошибок

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

const MyComponent = () => {
  const [data] = createResource(fetchData);

  return (
    <div>
      {data.loading && <p>Загрузка...</p>}
      {data.error && <p>Произошла ошибка: {data.error.message}</p>}
      {data() && <pre>{JSON.stringify(data(), null, 2)}</pre>}
    </div>
  );
};

При наличии ошибки можно вывести её сообщение на экран. В случае успешного запроса данные будут отображаться.

Особенности работы с createResource

  • Реактивность: Каждый вызов createResource и её возвращаемые значения, такие как data(), являются реактивными. Это означает, что если данные изменяются (например, при повторном запросе), компонент будет автоматически перерисован.

  • Оптимизация перерисовок: Solid.js использует эффективную модель работы с реактивностью, что минимизирует количество перерисовок. Если данные не изменились, компонент не будет повторно рендериться.

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

Заключение

createResource является мощным инструментом для работы с асинхронными данными в Solid.js. Он позволяет эффективно загружать данные с внешних источников, управлять состоянием загрузки и ошибок, а также использовать реактивность для автоматического обновления интерфейса. В отличие от более привычных решений, таких как useEffect в React, createResource обеспечивает более высокую производительность и простоту в работе с асинхронными запросами.