Роутинг
Простыми словами
Страницы, вложенные разделы, параметры в адресе и ленивая подгрузка кода.
@continuum-js/router обращается с URL так, как положено в этой модели: это Behavior. Смена роута — смена динамического региона; уход со страницы уничтожает её поддерево через дерево владения.
Роуты
import {
Router,
Outlet,
Link,
lazy,
type RouteDef,
} from "@continuum-js/router";
const routes: RouteDef[] = [
{
path: "",
component: Layout, // рендерит <Outlet /> для детей
children: [
{ path: "", component: Home },
{ path: "users/:id", component: UserPage },
{
path: "admin",
guard: (params) => isAdmin() || "/login",
component: AdminPage,
},
{ path: "*", component: NotFound },
],
},
];
<Router routes={routes} fallback={() => <NotFound />} />;:idстановитсяparams.id;*ловит остаток какparams["*"];- роут без
component— pathless layout: дети рендерятся насквозь; fallbackрендерится, когда не совпало ничего.
Вложенность: <Outlet>
Layout рендерит совпавшего ребёнка через <Outlet />:
function Layout() {
return (
<div>
<nav>
<Link href="/">Главная</Link>
<Link href="/users/1">Пользователь 1</Link>
</nav>
<Outlet />
</div>
);
}<Link> перехватывает простые левые клики в клиентскую навигацию и несёт класс active (точное совпадение для /, префикс для остальных; end форсирует точное; activeClass меняет имя).
Параметры — это Behavior
import { useParams } from "@continuum-js/router";
function UserPage() {
const params = useParams(); // Behavior<Params>, свои + предков
const user = resource(
params.map((p) => p.id).updates,
(id) => api.fetchUser(id),
);
return …;
}Регион ключуется идентичностью роута, а не URL: навигация /users/1 → /users/2 не пересобирает UserPage — обновляется только behavior params. То же обещание точечных обновлений — применённое к роутингу.
Guards
Guard — чистая функция от параметров: верните true, чтобы пропустить, или путь для редиректа. Редиректы применяются как replace-навигация, чтобы защищённый URL не засорял историю.
Разделение кода
lazy принимает thunk с литеральным import() — именно литерал заставляет бандлер выделить отдельный чанк:
const About = lazy(() => import("./pages/About.js"), {
fallback: () => <p>загрузка…</p>,
error: (e) => <p>не загрузилось</p>,
});Загрузчик выполняется при первом визите и кэшируется навсегда. Pending и error — обычные значения, которые рендерит регион; никакого Suspense.
Программная навигация
import { location, navigate } from "@continuum-js/router";
navigate("/users/2"); // pushState
navigate("/login", { replace: true }); // replaceState
const url = location(); // Behavior<URL> — синглтонlocation() следует и за кнопками назад/вперёд (popstate). Производные от него — обычный FRP: location().map((u) => u.searchParams.get("q")).
Незнакомый термин? Вся терминология этой документации объяснена в глоссарии.