1. Проблема: неправильный порядок маршрутов
Теперь перейдём к сложностям. Как говорилось в одном мемчике про программирование: "Если всё идеально работает, значит, вы что-то забыли". Но не переживайте, это не про нас! Мы разберём самые типичные проблемы и их решения.
В чём подвох?
Если маршруты в вашем коде неупорядочены, React может обработать неподходящий маршрут раньше, чем тот, который вы ожидаете. Например, если у вас есть маршрут для /products/:id и /products, и они определены в неправильном порядке, то динамический маршрут может перекрыть статический.
import { Route, Routes } from "react-router-dom";
function App() {
return (
<Routes>
<Route path="/products/:id" element={<ProductDetails />} />
<Route path="/products" element={<ProductList />} /> {/* Никогда не будет вызван */}
</Routes>
);
}
Как избежать?
Всегда указывайте более специфичные маршруты выше менее специфичных. Например:
function App() {
return (
<Routes>
<Route path="/products" element={<ProductList />} />
<Route path="/products/:id" element={<ProductDetails />} />
</Routes>
);
}
И тут можно добавить немножко TypeScript для типизации параметров :id:
import { useParams } from "react-router-dom";
interface ProductParams {
id: string;
}
function ProductDetails() {
const { id } = useParams<ProductParams>();
// Теперь id строго типизировано как строка
return <h1>Product ID: {id}</h1>;
}
2. Проблема: 404 страница не отображается
В чём подвох?
Иногда ваш маршрут /404 или компонент для обработки "страниц не найдено" просто не срабатывает. Это может случиться, если он определён некорректно или неправильно расположен.
Как избежать?
Гарантируйте, что ваш маршрут "по умолчанию" всегда обрабатывается последним, используя путь "*". Например:
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<NotFound />} /> {/* 404 страница */}
</Routes>
);
}
Теперь любая несуществующая страница будет попадать в обработчик NotFound.
3. Проблема: параметры маршрута не работают как надо
В чём подвох?
Ваш компонент может ломаться или рендерить некорректные данные, если параметры маршрута отсутствуют или невалидны. Например, если маршрут /products/:id ожидает обязательный параметр id, а пользователь вручную вводит /products/.
Как избежать?
Используйте типизацию и проверки. Например, с TypeScript можно заранее указать, что параметр является обязательным:
function ProductDetails() {
const { id } = useParams<ProductParams>();
if (!id) {
return <p>Error: Product ID is missing!</p>;
}
return <h1>Product ID: {id}</h1>;
}
Также убедитесь, что вы показываете пользователю адекватные ошибки, если данные некорректны. Например, можно вывести сообщение "Продукт не найден" вместо полного падения приложения.
4. Проблема: активные ссылки не подсвечиваются
В чём подвох?
Ваши ссылки, созданные с помощью компонента NavLink, не подсвечиваются, даже если текущий URL совпадает с маршрутом.
<NavLink to="/products">Products</NavLink>
Это может быть связано с тем, что вы забыли использовать className или не настроили стили для активных ссылок.
Как избежать?
Убедитесь, что вы добавили стили для активного состояния, либо используйте встроенный isActive атрибут:
<NavLink
to="/products"
className={({ isActive }) => (isActive ? "active-link" : "inactive-link")}
>
Products
</NavLink>
В CSS добавьте соответствующие стили:
.active-link {
font-weight: bold;
}
.inactive-link {
color: gray;
}
5. Проблема: загрузка всего приложения из-за больших маршрутов
В чём подвох?
Если ваше приложение разрастается, вы можете заметить, что страницы загружаются медленно. Это происходит потому, что React загружает весь бандл приложения сразу.
Как избежать?
Используйте динамическую загрузку компонентов с помощью React.lazy и Suspense:
import { lazy, Suspense } from "react";
const ProductDetails = lazy(() => import("./ProductDetails"));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/products/:id" element={<ProductDetails />} />
</Routes>
</Suspense>
);
}
Теперь маршрут /products/:id загрузит ProductDetails только тогда, когда он понадобится.
6. Проблема: защищённые маршруты не срабатывают корректно
В чём подвох?
Ваши защищённые маршруты могут не работать, если логика авторизации не согласована между компонентами или вы забыли учесть некоторые случаи, такие как истечение срока действия токена.
Как избежать?
Создайте компонент-обёртку для проверки авторизации. Например:
interface PrivateRouteProps {
isAuthenticated: boolean;
children: React.ReactNode;
}
function PrivateRoute({ isAuthenticated, children }: PrivateRouteProps) {
if (!isAuthenticated) {
return <Navigate to="/login" />;
}
return <>{children}</>;
}
Теперь вы можете защищать маршруты следующим образом:
<Route
path="/dashboard"
element={<PrivateRoute isAuthenticated={isLoggedIn}><Dashboard /></PrivateRoute>}
/>
7. Проблема: вложенные маршруты не работают
В чём подвох?
Если вы добавляете вложенные маршруты, но забываете использовать Outlet, подкомпоненты не будут отображаться.
Как избежать?
Обязательно добавьте Outlet в родительский маршрут:
function Products() {
return (
<div>
<h1>Products</h1>
<Outlet />
</div>
);
}
function App() {
return (
<Routes>
<Route path="/products" element={<Products />}>
<Route path=":id" element={<ProductDetails />} />
</Route>
</Routes>
);
}
Теперь вложенный маршрут /products/:id будет отображаться внутри компонента Products.
И вот так, друзья, изучив все эти проблемы и их решения, вы официально стали мастерами маршрутизации в React!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ