Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Загрузка данных: createResource и Suspense

Ресурс — это сигнал для асинхронных данных: он сам вызывает функцию загрузки, хранит результат и сообщает, идёт ли загрузка и не случилась ли ошибка. Так Solid загружает данные с сервера без ручных эффектов и флагов.

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

npx degit solidjs/templates/js blog
cd blog
npm install
npm run dev

Статьи будут приходить с тестового API https://jsonplaceholder.typicode.com.

createResource

Создайте компонент src/components/PostList.jsx:

// src/components/PostList.jsx
import { createResource, For, Show } from 'solid-js';
 
const fetchPosts = async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
  return res.json();
};
 
export default function PostList() {
  const [posts] = createResource(fetchPosts);
 
  return (
    <Show when={!posts.loading} fallback={<p>Загрузка...</p>}>
      <ul>
        <For each={posts()}>{(post) => <li>{post.title}</li>}</For>
      </ul>
    </Show>
  );
}

Выведите <PostList /> в src/App.jsx. Сначала на http://localhost:3000 появится «Загрузка...», затем список из пяти заголовков статей.

Что есть у ресурса

СвойствоЗначение
posts()Загруженные данные или undefined
posts.loadingtrue, пока идёт запрос
posts.errorОшибка, если запрос не удался

Второй элемент пары — объект с функциями refetch (загрузить заново) и mutate (заменить данные вручную): const [posts, { refetch }] = createResource(fetchPosts).

Ресурс с параметром

Если первым аргументом передать сигнал, ресурс будет перезагружаться при каждом его изменении:

// src/components/PostView.jsx
import { createSignal, createResource, Show } from 'solid-js';
 
const fetchPost = async (id) => {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  return res.json();
};
 
export default function PostView() {
  const [id, setId] = createSignal(1);
  const [post] = createResource(id, fetchPost);
 
  return (
    <div>
      <button onClick={() => setId(id() + 1)}>Следующая статья</button>
      <Show when={post()}>{(p) => <h2>{p().title}</h2>}</Show>
    </div>
  );
}

Каждое нажатие загружает следующую статью и показывает её заголовок. Значение сигнала приходит в fetchPost первым аргументом.

Suspense

Suspense показывает запасное содержимое, пока не загрузятся все ресурсы, прочитанные внутри него:

// src/App.jsx
import { Suspense } from 'solid-js';
import PostList from './components/PostList';
 
export default function App() {
  return (
    <Suspense fallback={<p>Загрузка блога...</p>}>
      <PostList />
    </Suspense>
  );
}

Так можно убрать Show из PostList и описать загрузку один раз на всю страницу.

Частая ошибка

Загружать данные в createEffect или onMount и складывать их в сигнал вручную. Это работает, но приходится самим заводить флаги загрузки и ошибки, а Suspense о таком запросе ничего не узнает. Для данных с сервера используйте createResource.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.