Data fetching patterns

Fresh — это современный подход к построению веб-приложений на JavaScript с использованием реактивных данных и серверной генерации. В его основе лежит идея минимизации сложной клиентской логики за счёт интеграции серверного рендеринга и прямого доступа к свежим данным.


Основные принципы Fresh

  1. Zero-runtime Fresh минимизирует количество кода, который выполняется на клиенте. Это достигается за счёт использования серверных компонентов и генерации HTML на сервере, что уменьшает нагрузку на браузер.

  2. Прямой доступ к данным Данные получают непосредственно на сервере через встроенные функции fetch или API маршруты. Это позволяет избежать излишней сериализации и передачи лишнего состояния на клиент.

  3. Мгновенный рендеринг Благодаря серверной генерации и минимальному клиентскому JavaScript, страницы загружаются быстрее, и пользователь видит контент практически мгновенно.


Работа с серверными маршрутами

Fresh использует API маршруты для работы с данными. Каждый маршрут представляет собой отдельный обработчик HTTP-запросов:

// routes/posts.js
export async function handler(req) {
  const res = await fetch("https://api.example.com/posts");
  const posts = await res.json();
  return new Response(JSON.stringify(posts), { status: 200 });
}

Особенности:

  • Обработчики могут быть асинхронными.
  • Возвращается объект Response, что позволяет полностью контролировать HTTP-ответ.
  • Логика обработки запросов полностью изолирована от клиентского кода.

Fetch внутри серверных компонентов

В Fresh данные обычно загружаются на сервере с помощью встроенного fetch. Компоненты получают данные сразу при рендеринге:

// components/PostList.js
export default async function PostList() {
  const res = await fetch("https://api.example.com/posts");
  const posts = await res.json();

  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

Ключевые моменты:

  • Серверный компонент может быть асинхронным.
  • Нет необходимости использовать useEffect или состояние для загрузки данных.
  • Рендеринг происходит только после получения данных, что исключает “пустые” состояния на странице.

Свежесть данных и кеширование

Fresh поддерживает разные стратегии работы с кешем:

  1. Cache-Control Можно управлять кешированием через HTTP-заголовки:
return new Response(JSON.stringify(posts), {
  headers: { "Cache-Control": "max-age=0, s-maxage=60" }
});
  • max-age=0 — данные не кэшируются на клиенте.
  • s-maxage=60 — данные кэшируются на сервере (CDN) на 60 секунд.
  1. ISR (Incremental Static Regeneration) Позволяет генерировать страницу один раз и автоматически обновлять её через заданный интервал.

  2. Stale-while-revalidate Старая версия страницы отдается мгновенно, а свежие данные подгружаются в фоне.


Работа с динамическими маршрутами

Для страниц с динамическими параметрами Fresh использует шаблоны маршрутов:

// routes/posts/[id].js
export async function handler(req, ctx) {
  const { id } = ctx.params;
  const res = await fetch(`https://api.example.com/posts/${id}`);
  const post = await res.json();
  return new Response(JSON.stringify(post));
}
  • ctx.params содержит параметры маршрута.
  • Можно комбинировать динамические маршруты с кешированием для увеличения производительности.

Комбинирование клиентских и серверных компонентов

Хотя Fresh ориентирован на серверный рендеринг, иногда необходима интерактивность:

// components/LikeButton.js
'use client';

import { useState } from "preact/hooks";

export default function LikeButton({ initialLikes }) {
  const [likes, setLikes] = useState(initialLikes);

  return (
    <button onCl ick={() => setLikes(likes + 1)}>
      Лайки: {likes}
    </button>
  );
}
  • Компоненты с 'use client' выполняются на клиенте.
  • Их можно вставлять внутрь серверных компонентов.
  • Такой подход позволяет комбинировать быстрый рендеринг с интерактивностью.

Практические советы при работе с Fresh

  • Минимизировать использование клиентского JavaScript, если интерактивность не требуется.
  • Все критичные данные загружать на сервере через fetch.
  • Управлять кешированием через HTTP-заголовки для оптимальной производительности.
  • Динамические маршруты использовать только там, где это действительно необходимо, чтобы не перегружать сервер.

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