Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Router #13

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
436 changes: 436 additions & 0 deletions src-russian/15_global_state.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src-russian/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
- [Формы и поля ввода](./view/05_forms.md)
- [Порядок выполнения](./view/06_control_flow.md)
- [Обработка ошибок](./view/07_errors.md)
- [Коммуникация Родитель-Ребёнок](./view/08_parent_child.md)
- [Коммуникация Родитель-Потомок](./view/08_parent_child.md)
- [Передача дочерних элементов другим компонентам](./view/09_component_children.md)
- [Без макросов: синтаксис строителя View](./view/builder.md)
- [Реактивность](./reactivity/README.md)
Expand Down
2 changes: 1 addition & 1 deletion src-russian/async/10_resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ view! {

```admonish sandbox title="Live example" collapsible=true

[Нажмите чтобы открыть CodeSandbox.](https://codesandbox.io/p/sandbox/10-resources-0-5-x6h5j6?file=%2Fsrc%2Fmain.rs%3A2%2C3)
[Нажмите, чтобы открыть CodeSandbox.](https://codesandbox.io/p/sandbox/10-resources-0-5-x6h5j6?file=%2Fsrc%2Fmain.rs%3A2%2C3)

<noscript>
Пожалуйста, включите Javascript для просмотра примеров.
Expand Down
2 changes: 1 addition & 1 deletion src-russian/async/11_suspense.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ view! {
[Нажмите, чтобы открыть CodeSandbox.](https://codesandbox.io/p/sandbox/11-suspense-0-5-qzpgqs?file=%2Fsrc%2Fmain.rs%3A1%2C1)

<noscript>
Please enable JavaScript to view examples.
Пожалуйста, включите Javascript для просмотра примеров.
</noscript>

<template>
Expand Down
4 changes: 2 additions & 2 deletions src-russian/interlude_projecting_children.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ where

## В заключение

Учтите, что это работает потому что компонентам `<Show/>` и `<Suspense/>` нужна иммутабельная ссылка на их дочерние элементы
(которую им может дать `.with_value` ), а не владение.
Учтите, что это работает потому, что компонентам `<Show/>` и `<Suspense/>` нужна иммутабельная ссылка на их дочерние элементы
(которую им может дать `.with_value` ), а не владение ими.

В иных случаях, может понадобиться пробрасывать свойства с владением через функцию, которая принимает `ChildrenFn`
и которая таким образом должна вызываться более одного раза.
Expand Down
2 changes: 1 addition & 1 deletion src-russian/reactivity/14_create_effect.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ set_num.set(2); // (nothing happens)

```admonish sandbox title="Live example" collapsible=true

[Кликните чтобы открыть CodeSandbox.](https://codesandbox.io/p/sandbox/14-effect-0-5-d6hkch?file=%2Fsrc%2Fmain.rs%3A1%2C1)
[Нажмите, чтобы открыть CodeSandbox.](https://codesandbox.io/p/sandbox/14-effect-0-5-d6hkch?file=%2Fsrc%2Fmain.rs%3A1%2C1)

<noscript>
Пожалуйста, включите Javascript для просмотра примеров.
Expand Down
162 changes: 162 additions & 0 deletions src-russian/router/16_routes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Описывание маршрутов

## Начало работы

Начать работу с маршрутизатором легко.

Перво-наперво нужно убедиться, что пакет `leptos_router` добавлен в зависимости проекта.
Как и `leptos`, маршрутизатор полагается на активацию особенности `csr`, `hydrate` или `ssr`.
К примеру, для добавления маршрутизатора в приложение с рендерингом на стороне клиента (CSR), можно вызвать:
```sh
cargo add leptos_router --features=csr
```

> Важно отметить, что `leptos_router` это пакет отдельный от самого `leptos`. Это означает, что всё, что есть в маршрутизаторе может
> быть задано в пользовательском пространстве _(англ. userland)_. Можно без проблем создать свой собственный маршрутизатор или
> вовсе обойтись без оного.

И импортировать сопутствующие типы из `leptos_router`, или как-то так:

```rust
use leptos_router::{Route, RouteProps, Router, RouterProps, Routes, RoutesProps};
```

или просто

```rust
use leptos_router::*;
```

## Объявление `<Router/>`

Поведение маршрутизатора определяется компонентом [`<Router/>`](https://docs.rs/leptos_router/latest/leptos_router/fn.Router.html). Обычно он вызывается где-то рядом с корнем приложения.

> Не следует вызывать `<Router/>` более одного раза. Помните, что маршрутизатор управляет глобальным состоянием:
> если у вас несколько маршрутизаторов, то какой из них будет решать когда менять URL?

Начнём с простого компонента `<App/>`, использующего маршрутизатор:

```rust
use leptos::*;
use leptos_router::*;

#[component]
pub fn App() -> impl IntoView {
view! {
<Router>
<nav>
/* ... */
</nav>
<main>
/* ... */
</main>
</Router>
}
}
```

## Объявление `<Routes/>`

Компонент [`<Routes/>`](https://docs.rs/leptos_router/latest/leptos_router/fn.Routes.html) это то, где задаются все маршруты по которым может переходить пользователь приложения.
Каждый из доступных маршрутов задается компонентом [`<Route/>`](https://docs.rs/leptos_router/latest/leptos_router/fn.Route.html).

Компонент `<Routes/>` должен находиться там, где содержимое должно меняться в зависимости от маршрута.
Всё что вне `<Routes/>` будет отображаться всегда, так что такие вещи как панель навигации или меню можно оставить за пределами `<Routes/>`.

```rust
use leptos::*;
use leptos_router::*;

#[component]
pub fn App() -> impl IntoView {
view! {
<Router>
<nav>
/* ... */
</nav>
<main>
// all our routes will appear inside <main>
<Routes>
/* ... */
</Routes>
</main>
</Router>
}
}
```

Отдельные маршруты задаются добавлением в `<Routes/>` дочерних компонентов `<Route/>`. `<Route/>` принимает свойства `path` и `view`.
Когда текущий URL удовлетворяет `path`, `view` будет создано и показано.

Свойство `path` может быть:

- статическим путём (`/users`),
- динамическим путём, именованные параметры начинаются с двоеточия (`/:id`),
- и/или шаблоном начинающийся со звёздочки (`/user/*any`)

Свойство `view` это функция, возвращающая представление. Тут подходит любой компонент без свойств, так же как и замыкание, возвращающее какой-то view.

```rust
<Routes>
<Route path="/" view=Home/>
<Route path="/users" view=Users/>
<Route path="/users/:id" view=UserProfile/>
<Route path="/*any" view=|| view! { <h1>"Not Found"</h1> }/>
</Routes>
```

> `view` принимает в качестве аргумента `Fn() -> impl IntoView`. Если у компонента нет свойств, его можно напрямую передать в свойство `view`. В данном примере, `view=Home` это сокращенная форма `|| view! { <Home/> }`.

Если перейти по адресу `/` или `/users`, то можно увидеть главную страницу или `<Users/>`.
Если перейти на `/users/3` или `/blahblah`, то будет профиль пользователя or страница ошибки 404 (`<NotFound/>`).
При каждом переходе, маршрутизатор определяет какой `<Route/>` подходит, и как следствие, какое содержимое должно быть
отображено там, где объявлен компонент `<Routes/>`.

Следует отметить, что маршруты можно задавать в любом порядке. Маршрутизатор использует систему баллов, чтобы определить
какой маршрут лучше подходит, а не просто берёт первый подходящий идя по списку сверху вниз.

Достаточно просто?

## Маршруты с условиями

`leptos_router` основан на том допущении, что в приложении один и только один компонент `<Routes/>`.
Он использует это, чтобы сгенерировать маршруты на стороне сервера, оптимизировать сопоставление маршрутов путём кеширование
вычисленных ветвей и отрендерить приложение.

Нельзя рендерить `<Routes/>` внутри условий используя другие компоненты как `<Show/>` или `<Suspense/>`.

```rust
// ❌ не делайте так!
view! {
<Show when=|| is_loaded() fallback=|| view! { <p>"Loading"</p> }>
<Routes>
<Route path="/" view=Home/>
</Routes>
</Show>
}
```

Вместо этого можно использовать вложенные маршруты, чтобы отрендерить `<Routes/>` единожды, и условно рендерить `<Outlet/>`:

```rust
// ✅ делайте так!
view! {
<Routes>
// parent route
<Route path="/" view=move || {
view! {
// only show the outlet if data have loaded
<Show when=|| is_loaded() fallback=|| view! { <p>"Loading"</p> }>
<Outlet/>
</Show>
}
}>
// nested child route
<Route path="/" view=Home/>
</Route>
</Routes>
}
```

Если это выглядит причудливо, не стоит беспокоиться! Следующий раздел этой книги посвящен такой вложенной маршрутизации.

Loading