React Router обеспечивает маршрутизацию внутри приложений на React, предоставляя возможности навигации, управления историей и синхронизации URL с состоянием приложения. Для приложений с комплексной логикой состояния часто необходимо согласовать маршруты с state management, таким как Redux, Zustand или Recoil, чтобы маршрутизация и состояние работали согласованно.
Поддержка единого источника правды требует, чтобы состояние приложения отражало текущий маршрут. Например, если в Redux хранится активная вкладка или фильтры списка, необходимо обновлять эти значения при изменении маршрута и наоборот.
Пример использования Redux с React Router:
import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useLocation, useNavigate } from 'react-router-dom';
import { setActiveTab } from './store/actions';
function TabSync() {
const location = useLocation();
const navigate = useNavigate();
const dispatch = useDispatch();
const activeTab = useSelector(state => state.ui.activeTab);
useEffect(() => {
const pathToTab = {
'/home': 'home',
'/profile': 'profile',
'/settings': 'settings'
};
dispatch(setActiveTab(pathToTab[location.pathname]));
}, [location.pathname, dispatch]);
useEffect(() => {
const tabToPath = {
home: '/home',
profile: '/profile',
settings: '/settings'
};
if (tabToPath[activeTab] !== location.pathname) {
navigate(tabToPath[activeTab]);
}
}, [activeTab, navigate, location.pathname]);
return null;
}
Ключевые моменты:
useLocation для отслеживания текущего
пути.Маршруты часто содержат параметры (/users/:id), которые
могут быть напрямую связаны с состоянием. Это особенно важно для форм,
фильтров и страниц деталей.
import { useParams } from 'react-router-dom';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { loadUser } from './store/actions';
function UserDetail() {
const { id } = useParams();
const dispatch = useDispatch();
useEffect(() => {
if (id) {
dispatch(loadUser(id));
}
}, [id, dispatch]);
return null;
}
Ключевые моменты:
useParams позволяет достичь реактивного
поведения при смене URL.В сложных приложениях полезно использовать middleware (например, в Redux) для управления побочными эффектами при навигации. Это позволяет централизованно обрабатывать переходы и состояние.
const navigationMiddleware = store => next => action => {
if (action.type === 'NAVIGATE') {
const { path } = action.payload;
window.history.pushState({}, '', path);
}
return next(action);
};
Ключевые моменты:
React Router поддерживает React.lazy и
Suspense для динамической загрузки компонентов, что важно
при интеграции с глобальным состоянием:
import { Suspense, lazy } from 'react';
import { Routes, Route } from 'react-router-dom';
const Dashboard = lazy(() => import('./Dashboard'));
const Reports = lazy(() => import('./Reports'));
function AppRoutes() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/reports" element={<Reports />} />
</Routes>
</Suspense>
);
}
Ключевые моменты:
Query-параметры (?filter=active) тесно связаны с
состоянием фильтров и пагинации:
import { useSearchParams } from 'react-router-dom';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { setFilter } from './store/actions';
function FilterSync() {
const [searchParams, setSearchParams] = useSearchParams();
const dispatch = useDispatch();
useEffect(() => {
const filter = searchParams.get('filter') || 'all';
dispatch(setFilter(filter));
}, [searchParams, dispatch]);
const updateFilter = (filter) => {
setSearchParams({ filter });
};
return null;
}
Ключевые моменты:
useSearchParams обеспечивает двустороннюю синхронизацию
состояния и URL.React Router предоставляет usePrompt или
unstable_useBlocker для предотвращения потери данных при
навигации:
import { useNavigate, useBlocker } from 'react-router-dom';
import { useState } from 'react';
function FormPage() {
const [isDirty, setIsDirty] = useState(false);
useBlocker((tx) => {
if (isDirty) {
const confirmLeave = window.confirm('Есть несохраненные изменения. Продолжить?');
if (confirmLeave) tx.retry();
} else {
tx.retry();
}
});
return null;
}
Ключевые моменты:
Эти практики обеспечивают надежную интеграцию React Router с state management, позволяя построить приложения, где URL и состояние всегда согласованы, асинхронные данные загружаются своевременно, а навигация контролируется централизованно.