Encodera

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

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

Оглавление

clientLoader: загрузка в браузере

Обычный loader выполняется только на сервере. Но некоторые данные есть лишь в браузере — например, черновик в localStorage. Для них модуль маршрута экспортирует clientLoader: такую же функцию загрузки, которая выполняется в браузере.

Черновики

Пусть на странице /drafts показывается черновик статьи, сохранённый в браузере. Добавьте маршрут route("drafts", "routes/drafts.tsx") и создайте файл:

// app/routes/drafts.tsx
import type { Route } from "./+types/drafts";
 
export async function clientLoader() {
  const draft = localStorage.getItem("draft") ?? "";
  return { draft };
}
 
export function HydrateFallback() {
  return <p>Загрузка черновика...</p>;
}
 
export default function Drafts({ loaderData }: Route.ComponentProps) {
  return loaderData.draft ? <p>{loaderData.draft}</p> : <p>Черновиков нет</p>;
}

При первом заходе сервер не может выполнить clientLoader — у него нет localStorage. Поэтому сервер отрисует HydrateFallback, а браузер, загрузив JavaScript, вызовет clientLoader и покажет черновик. При переходах по ссылкам clientLoader сразу выполняется в браузере.

Вместе с серверным загрузчиком

Если у маршрута есть и loader, и clientLoader, при переходах в браузере вызывается clientLoader. Серверные данные он может получить через serverLoader():

// app/routes/post.tsx
export async function clientLoader({ serverLoader }: Route.ClientLoaderArgs) {
  const serverData = await serverLoader();
  const readLater = localStorage.getItem("read-later") === String(serverData.post.id);
  return { ...serverData, readLater };
}

Компонент получит статью с сервера и флаг readLater из браузера. Так в браузере можно, например, добавить кеш, чтобы не запрашивать сервер повторно.

Запуск при первой загрузке

По умолчанию, если loader есть, при первом заходе используются только его данные, а clientLoader начинает работать с последующих переходов. Чтобы он выполнился и при первой загрузке, добавьте строку и HydrateFallback:

// app/routes/post.tsx
clientLoader.hydrate = true as const;

Что выбрать

НужноФункция
Данные из базы, секретные ключиloader
localStorage, данные о браузереclientLoader
Сервер плюс браузерный кешОба, serverLoader() внутри

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

Переносить в clientLoader запросы к базе или к API с секретным ключом. Код clientLoader попадает в браузер целиком, ключ увидит любой посетитель. Всё, что требует секретов или доступа к базе, оставляйте в loader.

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

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