TanStack Router — это современный роутер для React и других фреймворков, обеспечивающий декларативную маршрутизацию, поддержку асинхронных данных и гибкую работу с вложенными маршрутами. Zustand — это лёгкая и эффективная библиотека для управления состоянием в приложениях на React. Их интеграция позволяет строить приложения с централизованным управлением состоянием и согласованной маршрутизацией, сохраняя при этом высокую производительность.
Для начала создаём глобальный стор с Zustand:
import { create } from 'zustand';
export const useStore = create((set) => ({
user: null,
isAuthenticated: false,
setUser: (user) => set({ user, isAuthenticated: !!user }),
logout: () => set({ user: null, isAuthenticated: false }),
}));
Ключевые моменты:
setUser и logout позволяют
обновлять состояние и автоматически пересчитывать связанные
значения.Сначала необходимо определить маршруты:
import { createRouter, RouterProvider, Route } from '@tanstack/router';
import HomePage from './pages/HomePage';
import ProfilePage from './pages/ProfilePage';
import LoginPage from './pages/LoginPage';
const routes = [
new Route({ path: '/', component: HomePage }),
new Route({ path: '/login', component: LoginPage }),
new Route({
path: '/profile',
component: ProfilePage,
// Защита маршрута
beforeLoad: async () => {
const { isAuthenticated } = useStore.getState();
if (!isAuthenticated) throw new Error('Unauthorized');
}
}),
];
const router = createRouter({ routes });
Особенности интеграции:
beforeLoad используется для проверки состояния
аутентификации перед загрузкой маршрута.useStore.getState() позволяет синхронно получать
данные состояния вне React-компонента.Zustand позволяет связывать состояние приложения с TanStack Router для динамической маршрутизации. Например, можно автоматически перенаправлять пользователя при изменении состояния аутентификации:
import { useEffect } from 'react';
import { useStore } from './store';
import { useRouter } from '@tanstack/router';
function AuthWatcher() {
const { isAuthenticated } = useStore();
const router = useRouter();
useEffect(() => {
if (!isAuthenticated) {
router.navigate('/login');
}
}, [isAuthenticated, router]);
return null;
}
Заметки:
AuthWatcher не рендерит UI, а следит за
состоянием и инициирует навигацию.useEffect гарантирует, что редирект произойдёт сразу
после изменения состояния.TanStack Router позволяет работать с асинхронными загрузками данных, которые могут зависеть от состояния Zustand:
const ProfilePage = () => {
const { user, setUser } = useStore();
useEffect(() => {
if (!user) {
fetch('/api/profile')
.then(res => res.json())
.then(data => setUser(data));
}
}, [user, setUser]);
if (!user) return <div>Загрузка...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
};
Важные моменты:
beforeLoad
или onLoad.Для сложных приложений можно создать реактивные эффекты, которые связывают состояние и маршрут:
useStore.subscribe(
(state) => state.isAuthenticated,
(isAuthenticated) => {
if (!isAuthenticated) router.navigate('/login');
}
);
Преимущества:
beforeLoad
для синхронной проверки состояния перед загрузкой компонента.const routes = [
new Route({ path: '/', component: HomePage }),
new Route({ path: '/login', component: LoginPage }),
new Route({
path: '/profile',
component: ProfilePage,
beforeLoad: async () => {
const { isAuthenticated } = useStore.getState();
if (!isAuthenticated) throw new Error('Unauthorized');
},
}),
];
const router = createRouter({ routes });
function App() {
return (
<>
<RouterProvider router={router} />
<AuthWatcher />
</>
);
}
Особенности конструкции:
AuthWatcher поддерживает согласованность между
состоянием и маршрутизацией, создавая полностью реактивное
приложение.Эта схема интеграции позволяет строить масштабируемые приложения с безопасной маршрутизацией и единым источником правды для состояния.