Зависимости в контексте

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

Декларация зависимостей

Каждый маршрут в TanStack Router может иметь зависимости, определяемые через функции loader, action и component. Зависимости позволяют маршруту автоматически перезапускать свои вычисления при изменении определённых данных.

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

const userRoute = createRoute({
  path: '/user/:id',
  loader: ({ params }) => fetch(`/api/user/${params.id}`).then(res => res.json()),
});

В этом примере loader зависит от параметра маршрута id. Любое изменение id приведёт к повторному вызову загрузчика.

Типы зависимостей

  1. Параметры маршрута (params) – изменения значений, переданных в URL, автоматически инициируют повторную загрузку.
  2. Квери-параметры (search) – включают значения из строки запроса; обновление параметров запроса может вызвать повторный рендер.
  3. Внешние данные (context) – состояние приложения или глобальные объекты, которые передаются через router context.
  4. Асинхронные ресурсы (loader и action) – зависят от предыдущих результатов загрузки или других маршрутов.

Контекст и зависимости

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

const appRouter = createRouter({
  routeTree: rootRoute,
  defaultPreload: 'intent',
  context: {
    user: null,
  },
});

Здесь context.user может быть источником зависимости для всех маршрутов, использующих данные пользователя. Любое обновление контекста инициирует реактивное обновление зависимых маршрутов.

Оптимизация повторного рендеринга

TanStack Router поддерживает тонкое отслеживание зависимостей, что позволяет:

  • Перезапускать loader только для изменённых данных.
  • Минимизировать ререндер компонентов, зависящих от конкретных параметров.
  • Кешировать результаты асинхронных операций, если зависимости не изменились.

Для этого можно использовать объект dependencies в loader:

const postsRoute = createRoute({
  path: '/posts',
  loader: async ({ context }) => {
    return fetch(`/api/posts?userId=${context.user.id}`).then(res => res.json());
  },
  dependencies: ({ context }) => [context.user.id],
});

Любое изменение context.user.id приведёт к повторной загрузке постов, при этом другие изменения контекста не будут затрагивать этот маршрут.

Асинхронные зависимости и параллельная загрузка

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

const dashboardRoute = createRoute({
  path: '/dashboard',
  loader: async ({ context }) => {
    const [notifications, messages] = await Promise.all([
      fetch('/api/notifications').then(res => res.json()),
      fetch('/api/messages').then(res => res.json()),
    ]);
    return { notifications, messages };
  },
});

Такой подход сокращает время ожидания и обеспечивает единый объект с результатами всех зависимостей.

Рекурсивные зависимости

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

const profileRoute = createRoute({
  path: '/profile',
  loader: async ({ context }) => fetch(`/api/profile/${context.user.id}`).then(res => res.json()),
  children: [
    createRoute({
      path: 'settings',
      loader: async ({ parentData }) => {
        const profile = parentData.profile;
        return fetch(`/api/settings/${profile.id}`).then(res => res.json());
      },
    }),
  ],
});

В данном примере дочерний маршрут settings зависит от данных родителя profile, что обеспечивает согласованность состояния.

Кеширование и инвалидация

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

const commentsRoute = createRoute({
  path: '/comments',
  loader: async ({ context }) => fetch(`/api/comments`).then(res => res.json()),
  invalidateOn: ({ context }) => [context.newCommentFlag],
});

Маршрут перезагрузится только при изменении context.newCommentFlag, сохраняя результаты предыдущих запросов, если зависимости не изменились.


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