Пользовательские хуки на основе встроенных

TanStack Router предоставляет мощную систему маршрутизации, ориентированную на React и другие фреймворки, с упором на реактивное состояние и декларативное управление маршрутами. Важной частью этой системы является возможность создания пользовательских хуков, основанных на встроенных хуках маршрутизатора, таких как useRouter, useRoute, useParams и useMatches. Эти хуки позволяют инкапсулировать повторяющуюся логику, повышать читаемость кода и облегчать повторное использование функций.


Создание пользовательских хуков

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

import { useRoute, useParams } from '@tanstack/router';

function useUserData() {
  const route = useRoute();
  const params = useParams();

  const userId = params.userId;

  // Дополнительная логика, например, выборка данных из API или локального состояния
  const [user, setUser] = React.useState(null);

  React.useEffect(() => {
    if (userId) {
      fetch(`/api/users/${userId}`)
        .then(res => res.json())
        .then(data => setUser(data));
    }
  }, [userId]);

  return { user, route, userId };
}

Здесь пользовательский хук useUserData использует встроенные useRoute и useParams, добавляя асинхронную логику загрузки данных пользователя. Такой подход позволяет использовать хук в разных компонентах без дублирования кода.


Преимущества пользовательских хуков

  1. Инкапсуляция логики Вся работа с маршрутными параметрами и асинхронными операциями скрыта внутри одного хука, что делает компонент более чистым.

  2. Повторное использование Один хук можно использовать в разных местах приложения, минимизируя вероятность ошибок.

  3. Поддержка типизации TanStack Router поддерживает TypeScript, поэтому пользовательские хуки можно типизировать для строгого контроля параметров:

import { useParams } from '@tanstack/router';

interface UserParams {
  userId: string;
}

function useTypedUserParams() {
  const params = useParams();
  return params;
}

Расширение встроенных хуков

Помимо обертки для добавления логики, можно создавать хуки для работы с несколькими маршрутами одновременно:

import { useMatches } from '@tanstack/router';

function useCurrentUserAndSettings() {
  const matches = useMatches();

  const userMatch = matches.find(m => m.route.id === 'userRoute');
  const settingsMatch = matches.find(m => m.route.id === 'settingsRoute');

  const user = userMatch?.data.user;
  const settings = settingsMatch?.data.settings;

  return { user, settings };
}

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


Использование хуков с асинхронными данными

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

import { useRouteLoaderData } from '@tanstack/router';

function usePostData(postId) {
  const data = useRouteLoaderData({ routeId: 'postRoute', params: { postId } });

  // Дополнительная обработка данных
  const post = data ? { ...data, title: data.title.toUpperCase() } : null;

  return post;
}

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


Сочетание пользовательских хуков и глобального состояния

Пользовательские хуки удобно комбинировать с глобальными состояниями, например, через React Context или Zustand. Это позволяет синхронизировать данные маршрутов с состоянием приложения:

import { useParams } from '@tanstack/router';
import { useUserStore } from '../stores/userStore';

function useSyncUser() {
  const { userId } = useParams();
  const { setUser } = useUserStore();

  React.useEffect(() => {
    if (userId) {
      fetch(`/api/users/${userId}`)
        .then(res => res.json())
        .then(setUser);
    }
  }, [userId, setUser]);
}

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


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

  • Минимизировать побочные эффекты: пользовательский хук должен в основном фокусироваться на вычислении и подготовке данных, а побочные эффекты — через useEffect.
  • Использовать типизацию: строгое определение типов параметров и данных повышает стабильность и упрощает поддержку.
  • Комбинировать хуки: один пользовательский хук может использовать другие хуки для создания более сложной логики без дублирования кода.
  • Разделять ответственность: один хук — одна задача. Это улучшает читаемость и тестируемость.