Domain-driven routing — подход к построению маршрутизации, при котором структура маршрутов отражает предметную область приложения, а не только URL-пути. TanStack Router предоставляет гибкие инструменты для реализации такого подхода, позволяя создавать маршруты, тесно связанные с бизнес-логикой.
В основе Domain-driven routing лежит идея разделения маршрутов по доменным модулям. Каждый модуль отвечает за отдельную область приложения: пользователи, продукты, заказы и т.д. Такой подход повышает читаемость, поддерживаемость кода и позволяет легко масштабировать приложение.
import { createRouter, createRoute } from '@tanstack/router';
const usersRoute = createRoute({
path: '/users',
component: UsersPage,
children: [
createRoute({ path: '/:userId', component: UserProfile }),
createRoute({ path: '/:userId/edit', component: UserEditPage }),
],
});
const productsRoute = createRoute({
path: '/products',
component: ProductsPage,
children: [
createRoute({ path: '/:productId', component: ProductDetail }),
createRoute({ path: '/new', component: ProductCreate }),
],
});
const router = createRouter({
routeTree: [usersRoute, productsRoute],
});
Ключевой момент: маршруты сгруппированы по функциональным областям, а вложенные маршруты отражают иерархию данных (например, пользователь → профиль → редактирование).
TanStack Router поддерживает загрузку данных на уровне маршрута через
loader и использование params для передачи
доменной информации:
const userDetailRoute = createRoute({
path: '/users/:userId',
component: UserProfile,
loader: async ({ params }) => {
const user = await fetchUserById(params.userId);
return { user };
},
});
const productDetailRoute = createRoute({
path: '/products/:productId',
component: ProductDetail,
loader: async ({ params }) => {
const product = await fetchProductById(params.productId);
return { product };
},
});
Преимущество: маршруты сами отвечают за загрузку необходимых данных, а компоненты получают их через контекст маршрутизатора, что уменьшает зависимость от глобального состояния.
TanStack Router позволяет строить глубокую вложенную структуру, что
идеально подходит для доменно-ориентированной архитектуры. Вложенные
маршруты используют outlet для рендеринга дочерних
компонентов:
function UsersPage() {
return (
Пользователи
);
}
function UserProfile({ loaderData }) {
return (
{loaderData.user.name}
Email: {loaderData.user.email}
);
}
Важно: дочерние маршруты наследуют контекст родительского маршрута, включая данные и параметры, что упрощает работу с вложенными сущностями.
Использование TypeScript в сочетании с TanStack Router позволяет добиться строгой типизации параметров маршрутов и данных:
interface UserParams {
userId: string;
}
const userDetailRoute = createRoute({
path: '/users/:userId',
component: UserProfile,
loader: async ({ params }) => {
const user = await fetchUserById(params.userId);
return { user };
},
});
Эффект: ошибки типа в параметрах маршрутов или при получении данных становятся видимыми на этапе компиляции, снижая вероятность runtime-ошибок.
lazy import, минимизируя
начальный вес приложения.const ordersRoute = createRoute({
path: '/users/:userId/orders',
component: OrdersPage,
loader: async ({ params }) => fetchOrdersForUser(params.userId),
});
TanStack Router предоставляет возможность хранить и управлять состоянием на уровне маршрутов. Состояние маршрута может включать фильтры, сортировку или данные формы, что особенно полезно для сложных доменных интерфейсов:
const ordersRoute = createRoute({
path: '/orders',
component: OrdersPage,
useLoaderData: true,
defaultSearchParams: {
status: 'all',
},
});
Вывод: состояние маршрута тесно связано с предметной областью и автоматически синхронизируется с URL, облегчая поддержку истории и навигации.