React: роутинг и состояние
Одностраничное приложение выросло: уже не один экран. Откроем навигацию по URL без перезагрузки, научимся делить состояние и подгружать данные с сервера — полный набор для реального проекта.
React Router: страницы по URL
Браузерные «страницы» в SPA — это маршруты внутри приложения. URL меняется, страница не перезагружается. Популярное решение — React Router.
npm install react-router-dom
// main.jsx
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Домой</Link>
<Link to="/about">О нас</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/products/:id" element={<Product />} />
</Routes>
</BrowserRouter>
);
}
Context: общие данные без прокидывания
Корзину нужна в шапке, каталоге и на странице товара. Пробрасывать через props в пять уровней — больно. Context даёт «глобальное» хранилище для состояния приложения.
const CartContext = createContext(null);
function CartProvider({ children }) {
const [items, setItems] = useState([]);
const add = (id) =>
setItems((prev) => [...prev, id]);
return (
<CartContext.Provider value={{ items, add }}>
{children}
</CartContext.Provider>
);
}
// в любом компоненте ниже:
function Header() {
const { items } = useContext(CartContext);
return <div>В корзине: {items.length}</div>;
}
Данные с сервера: эффекты
Запрос выполняется в useEffect; результат складываем в состояние; пока грузится — показываем спиннер.
import { useEffect, useState } from "react";
function Products() {
const [list, setList] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/products")
.then((r) => r.json())
.then(setList)
.finally(() => setLoading(false));
}, []); // [] — выполнить один раз при монтировании
return loading ? <p>Загрузка…</p> : <ul>
{list.map((p) => <li key={p.id}>{p.name}</li>)}
</ul>;
}
ℹ️
Мемоизация
useMemo бережёт дорогие вычисления, useCallback — стабильность функций-колбэков. Правило-оберег: не добавляйте их «на всякий случай» — только при измеримой проблеме.💡
Для больших приложений появляются библиотеки вроде Redux/Zustand. Но правило номер один: начинайте с useState + Context. Большую часть случаев они решают без дополнительных зависимостей.