Мемоизация данных маршрутов

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


Основные понятия мемоизации

Мемоизация — это сохранение результатов вычислений для повторного использования. В контексте TanStack Router мемоизация применяется к loader-функциям, которые отвечают за получение данных для маршрута. Если маршрут уже загружался с теми же параметрами, TanStack Router может вернуть ранее сохранённые данные вместо повторного запроса.

Принципы работы мемоизации в маршрутах:

  1. Идентификация маршрута Каждый маршрут имеет уникальный путь и набор параметров. Мемоизация использует комбинацию маршрута и текущих параметров для хранения данных.

  2. Кэширование данных Загруженные данные помещаются в внутренний кэш. При повторном обращении с теми же параметрами кэш проверяется и возвращается результат без повторного вызова loader-функции.

  3. Обновление данных Данные могут быть обновлены через специальные методы маршрутизатора (invalidate, refresh) либо при изменении зависимостей, указанных в конфигурации маршрута.


Настройка мемоизации

Для использования мемоизации loader-функции в TanStack Router необходимо:

import { createRouter, createRoute } from '@tanstack/router';

const userRoute = createRoute({
  path: '/user/:userId',
  loader: async ({ params }) => {
    const response = await fetch(`/api/users/${params.userId}`);
    return response.json();
  },
  // Включение мемоизации
  memoize: true
});

const router = createRouter({
  routes: [userRoute],
});

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

  • Опция memoize: true активирует хранение результатов loader-функции в кэше.
  • Кэш привязывается к конкретным параметрам маршрута (params) и query-параметрам.
  • Если параметры изменились, TanStack Router автоматически вызывает loader снова.

Контроль кэша

TanStack Router предоставляет несколько способов управлять кэшированными данными:

  1. Инвалидация кэша для конкретного маршрута
router.invalidate('userRoute', { params: { userId: 42 } });
  1. Полная перезагрузка данных маршрута
router.refresh('userRoute');
  1. Автоматическое обновление при изменении зависимостей Loader может принимать дополнительные зависимости, чтобы автоматически сбрасывать кэш при их изменении:
const userRoute = createRoute({
  path: '/user/:userId',
  loader: async ({ params, context }) => {
    const token = context.authToken;
    const response = await fetch(`/api/users/${params.userId}`, {
      headers: { Authorization: `Bearer ${token}` },
    });
    return response.json();
  },
  memoize: true,
  deps: ['authToken'], // Кэш сбрасывается при изменении токена
});

Работа с nested routes и мемоизацией

Для вложенных маршрутов мемоизация работает на уровне каждого маршрута. Это позволяет:

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

Пример:

const userRoute = createRoute({ path: '/user/:userId', loader: fetchUser, memoize: true });
const postsRoute = createRoute({ path: 'posts', parent: userRoute, loader: fetchPosts, memoize: true });

const router = createRouter({ routes: [userRoute, postsRoute] });

В этом случае данные пользователя сохраняются при переходе между вкладками (/user/1/posts, /user/1/settings), что повышает производительность.


Практические рекомендации

  • Использовать мемоизацию для часто посещаемых страниц с одинаковыми параметрами.
  • Не мемоизировать данные, которые часто меняются, чтобы не возвращать устаревшую информацию.
  • Комбинировать мемоизацию с механизмом инвалидации, чтобы данные оставались актуальными.
  • Следить за зависимостями loader через deps, чтобы кэш обновлялся при изменении критичных значений, например токена аутентификации или фильтров.

Пример комплексного сценария

const productRoute = createRoute({
  path: '/products/:productId',
  loader: async ({ params }) => {
    const response = await fetch(`/api/products/${params.productId}`);
    return response.json();
  },
  memoize: true,
  deps: ['userPreferences'],
});

const reviewRoute = createRoute({
  path: 'reviews',
  parent: productRoute,
  loader: async ({ params }) => {
    const response = await fetch(`/api/products/${params.productId}/reviews`);
    return response.json();
  },
  memoize: true,
});

const router = createRouter({ routes: [productRoute, reviewRoute] });

// Переход между продуктами с сохранением кэша для уже посещённых
router.navigate('/products/123/reviews');
router.navigate('/products/123'); // Данные продукта берутся из кэша
router.navigate('/products/124'); // Кэш сбрасывается для нового productId

Использование мемоизации в TanStack Router значительно повышает отзывчивость приложения и снижает нагрузку на сервер, сохраняя данные маршрутов там, где это оправдано по логике работы.