Encodera

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

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

Оглавление

Загрузка данных для маршрутов

Странице статьи нужны данные статьи, а странице списка — список. Solid Router умеет загружать их сам: функция query описывает запрос и кеширует результат, createAsync читает его в компоненте, а атрибут preload у маршрута начинает загрузку ещё до того, как страница отрисуется.

Функции запросов

Соберите запросы к API в одном файле src/api/posts.js:

// src/api/posts.js
import { query } from '@solidjs/router';
 
const API = 'https://jsonplaceholder.typicode.com';
 
export const getPosts = query(async () => {
  const res = await fetch(`${API}/posts?_limit=10`);
  return res.json();
}, 'posts');
 
export const getPost = query(async (id) => {
  const res = await fetch(`${API}/posts/${id}`);
  return res.json();
}, 'post');

Второй аргумент query — имя для кеша. Повторный вызов getPost('7') в течение короткого времени вернёт уже загруженный результат вместо нового запроса.

Чтение в компоненте

// src/pages/Posts.jsx
import { For } from 'solid-js';
import { A, createAsync } from '@solidjs/router';
import { getPosts } from '../api/posts';
 
export default function Posts() {
  const posts = createAsync(() => getPosts());
 
  return (
    <ul>
      <For each={posts()}>
        {(post) => (
          <li>
            <A href={`/posts/${post.id}`}>{post.title}</A>
          </li>
        )}
      </For>
    </ul>
  );
}

createAsync возвращает функцию-геттер, как сигнал. На http://localhost:3000/posts появится список из десяти статей с сервера.

Страница статьи

// src/pages/Post.jsx
import { Show } from 'solid-js';
import { useParams, createAsync } from '@solidjs/router';
import { getPost } from '../api/posts';
 
export default function Post() {
  const params = useParams();
  const post = createAsync(() => getPost(params.id));
 
  return (
    <Show when={post()}>
      <article>
        <h1>{post().title}</h1>
        <p>{post().body}</p>
      </article>
    </Show>
  );
}

Функция внутри createAsync читает params.id, поэтому при переходе на другую статью запрос выполнится заново. На /posts/1 видны заголовок и текст первой статьи.

Предзагрузка

// src/index.jsx
import { getPosts, getPost } from './api/posts';
 
<Route path="/posts" component={Posts} preload={() => getPosts()} />
<Route path="/posts/:id" component={Post} preload={({ params }) => getPost(params.id)} />

preload вызывается при переходе на маршрут и даже при наведении мыши на ссылку A. Когда компонент вызовет ту же функцию, данные уже будут в кеше.

Загрузка и ошибки

Пока данные идут, createAsync ведёт себя как ресурс: оберните {props.children} в макете App в Suspense с fallback, а при желании и в ErrorBoundary — так загрузка и ошибки всех страниц обрабатываются в одном месте.

ИнструментЗадача
query(fn, 'имя')Описать запрос и кешировать его
createAsync(() => ...)Прочитать данные в компоненте
preload у RouteНачать загрузку заранее

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

Вызывать getPost(params.id) прямо в теле компонента и ждать результат через await. Тело компонента синхронное и выполняется один раз: компонент не дождётся данных и не обновится при смене статьи. Всегда оборачивайте вызов в createAsync(() => ...).

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

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