Solid Router¶
В современной веб-разработке маршрутизатор - это программный компонент, отвечающий за обработку клиентских запросов и определяющий, какой компонент следует отобразить, с помощью маршрутизации на стороне сервера или на стороне клиента. При поступлении запроса от клиента маршрутизатор оценивает URL и решает, какой контроллер или компонент на стороне сервера должен обработать этот запрос или быть отображен.
Solid Router - это простой и удобный в использовании универсальный маршрутизатор для приложений Solid. Он работает как на клиенте, так и на сервере. Маршруты задаются с помощью простого синтаксиса JSX и могут быть вложенными. Однако маршруты можно передавать и в виде объекта конфигурации.
Solid Router обладает множеством замечательных возможностей, одной из которых является поддержка вложенной маршрутизации, позволяющей изменять определенную часть компонента, а не заменять его полностью.
Он поддерживает все методы Solid SSR и имеет встроенные переходы Solid, поэтому его можно свободно использовать с суспензиями, ресурсами и "ленивыми" компонентами. Solid Router также позволяет определить функцию данных, которая загружается параллельно с маршрутами (render-as-you-fetch).
Дополнительную информацию о Solid Router можно найти на Solid Router GitHub page.
Начало работы¶
Для того чтобы начать работу с Solid Router, необходимо установить его в проект, поскольку по умолчанию он не установлен. После этого необходимо настроить маршрутизатор и определить некоторые маршруты.
Установка¶
Давайте перейдем к установке маршрутизатора. Для этого нам нужно установить маршрутизатор с помощью NPM, Yarn или вашего любимого менеджера пакетов.
1 2 3 4 5 |
|
Настройка¶
Теперь, когда маршрутизатор установлен, мы можем его настроить и определить некоторые маршруты. Начнем с импорта маршрутизатора в наш корневой файл Index
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Теперь, когда маршрутизатор настроен, мы можем определить некоторые маршруты. Начнем с того, что сделаем компонент App
нашей домашней страницей или маршрутом /
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
В приведенном выше коде мы импортировали компоненты Route
и Routes
из Solid Router и определили маршрут для главной страницы. Компонент Route
принимает свойство path
, которое представляет собой путь URL, которому будет соответствовать маршрут. Свойство component
- это компонент, который будет отображаться при совпадении с маршрутом. Компонент Routes
используется для группировки маршрутов и необходим для вложенных маршрутов. Этот компонент используется для того, чтобы показать, где должны быть отображены маршруты.
Вы можете добавить несколько маршрутов в компонент Routes
, и они будут отображаться каждый раз, когда URL-адрес будет соответствовать пути маршрута. Добавим маршрут для страниц /about
и /contact
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Примечание
Если вы хотите лениво загружать свои компоненты, чтобы они загружались только при совпадении маршрута, вы можете использовать функцию lazy
из solid-js
для ленивой загрузки своих компонентов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Теперь, когда определены маршруты, мы можем переходить на страницы /about
и /contact
. Давайте добавим несколько ссылок в компонент App
, чтобы можно было переходить на другие страницы. Для добавления ссылок в маршруты можно использовать компонент A
из Solid Router. Добавим ссылки на страницы /about
и /contact
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Создание ссылок на другие маршруты¶
Компонент A
¶
Компонент A
используется для создания ссылок на другие маршруты в вашем приложении. Компонент A
также принимает свойство href
, которое представляет собой URL-путь, по которому будет осуществляться переход по ссылке. Компонент A
также принимает свойство activeClass
, которое представляет собой класс, который будет применен к ссылке, когда текущий путь маршрута совпадет с путем ссылки.
Вот краткий пример того, как может выглядеть базовое приложение Solid с Solid Router и как использовать компонент A
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Приведем пример использования компонента A
и его свойства activeClass
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Примечание
Будьте внимательны при использовании свойства activeClass
, поскольку по умолчанию в соответствие включаются маршруты, являющиеся потомками или иным образом вложенными в совпадающий путь (например, /about
будет соответствовать /about/me
и /about/me/you
). Однако можно использовать булево свойство `end
для точного соответствия пути (например, /about
будет соответствовать только /about
). Свойство end
особенно полезно для ссылок на корневой маршрут /
, который будет соответствовать всем путям.
Вот список всех свойств, которые принимает компонент A
.
Свойства | Тип | Описание |
---|---|---|
href | string | Путь маршрута, на который нужно перейти. Он будет разрешен относительно маршрута, в котором находится ссылка, но перед ним можно поставить / , чтобы вернуться к корню. |
activeClass | string | Класс, который будет применяться к ссылке, когда текущий путь маршрута совпадает с путем ссылки. |
end | boolean | Если true , то ссылка считается активной только тогда, когда текущее местоположение точно совпадает с href ; если false , то проверяется, начинается ли текущее местоположение с href |
noScroll | boolean | Если true , то отключается стандартное поведение прокрутки к верху новой страницы |
replace | boolean | Если true , то не добавлять новую запись в историю браузера. (По умолчанию новая страница будет добавлена в историю браузера, поэтому нажатие кнопки назад приведет к переходу на предыдущий маршрут). |
state | unknown | Вставить это значение в стек истории при навигации |
inactiveClass | string | Класс, который должен отображаться, когда ссылка неактивна (когда текущее местоположение не соответствует ссылке) |
Компонент Navigate
¶
Solid Router предоставляет компонент Navigate
, который работает аналогично компоненту A
, но сразу после отображения компонента осуществляет переход по указанному пути. Он также использует свойство href
, но у вас есть дополнительная возможность передать в href
функцию, возвращающую путь для перехода:
1 2 3 4 5 6 7 8 9 10 11 |
|
Динамические маршруты¶
Если путь не известен заранее, можно рассматривать часть пути как гибкий параметр, который передается компоненту. Например, если необходимо перейти к записи блога с определенным идентификатором, можно использовать динамический маршрут.
Вот краткий пример создания динамического маршрута.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
В приведенном выше фрагменте кода мы добавили динамический маршрут с именем user
, который принимает параметр :id
. Параметр :id
будет передаваться компоненту User
через примитив useParams
. Подробнее о примитивах Solid Router мы поговорим позже.
Приведем пример использования динамического маршрута в компоненте User
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Для доступа к динамическим параметрам маршрута можно использовать объект params
. В приведенном примере мы получили доступ к параметру id
. Параметры можно использовать даже в таких примитивах, как createResource
и createSignal
:
Вот пример того, как это может выглядеть в примитиве createResource
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
В приведенном выше фрагменте кода мы передали параметр id
примитиву createResource
. Это означает, что функция fetchUser
будет вызываться каждый раз при изменении параметра id
. Это удобно, если необходимо получать новые данные о пользователе при каждом изменении параметра id
.
Необязательные параметры¶
Вы также можете сделать параметр необязательным, добавив символ ?
после имени параметра. Например, если вы хотите сделать параметр id
необязательным, то сделайте следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Необязательный маршрут /user/:id?
будет соответствовать /user
и /user/123
, но не /user/123/comment
.
Маршруты/параметры диких символов¶
Маршруты с подстановочными знаками - это маршруты, которые соответствуют любому пути-потомку в пределах заданного пути.
Параметр также можно сделать подстановочным, добавив *
после имени параметра. Например, если необходимо сделать параметр id
подстановочным, то можно сделать следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Маршрут с подстановочным символом /user/*
будет соответствовать маршрутам /user
, /user/123
, /user/123/comment
, /user/123/comment/456
и т.д.
Если вы хотите получить доступ к параметру wildcard, вы можете назвать его:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Доступ к параметру wildcard
осуществляется так же, как и к параметру динамического маршрута:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Примечание
Токен *
должен быть последним в пути маршрута. Например, /user/*id
является допустимым, а /user/id*
и /user/*id/foo
- нет.
Множественные пути¶
Маршруты также поддерживают определение нескольких путей с помощью массива. Это позволяет маршруту оставаться смонтированным и не перерисовываться при переключении между двумя или более местами, которым он соответствует:
1 2 |
|
Функции данных¶
В предыдущих примерах компонент User загружается в ленивом режиме, а затем происходит выборка данных. С помощью функций данных маршрута мы можем начать получать данные параллельно с загрузкой маршрута, чтобы использовать их как можно быстрее.
Для этого создайте функцию, которая получает и возвращает данные с помощью createResource
. Затем передайте эту функцию в свойство data
компонента Route
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Функция data
будет вызвана после загрузки маршрута, а доступ к результату можно получить, вызвав useRouteData
в компоненте маршрута.
1 2 3 4 5 |
|
1 2 3 4 5 |
|
Поскольку функция data имеет только один аргумент, которым является объект, содержащий информацию о маршруте, например
Ключ | Тип | Описание |
---|---|---|
params | object | Параметры маршрута (то же значение, что и при вызове функции useParams() внутри компонента маршрута) |
location | { pathname, search, hash, query, state, key} | Объект, который можно использовать для получения дополнительной информации о пути (соответствует useLocation()) |
navigate | (to: string, options?: NavigateOptions) => void | Функция, которую можно вызвать для перехода к другому маршруту (соответствует useNavigate()) |
data | unknown | Данные, возвращаемые родительской функцией data, если таковая имеется. (Данные будут проходить через все промежуточные вложенности.) |
Общим шаблоном является экспорт функции данных, соответствующей маршруту, в специальный файл route.data.js|ts
. Таким образом, функция данных может быть импортирована без загрузки чего-либо еще.
1 2 3 4 5 6 7 8 |
|
Импортировать функцию fetchUser больше не нужно, поскольку она используется не здесь, а в файле [id].data.js
.
Вложенные маршруты¶
Вложенные маршруты - это еще один способ определения маршрутов. Они полезны, когда у вас много маршрутов и вы хотите сгруппировать их вместе. Они также позволяют определить компонент макета, который будет использоваться для всех вложенных маршрутов.
Приведем небольшой пример кода, показывающий разницу между обычными и вложенными определениями маршрутов:
1 |
|
1 2 3 |
|
/users/:id
отображает компонент <User/>
, а /users/
- пустой маршрут.
Маршрут задается только для листовых узлов Route (внутренних компонентов Route
). Если вы хотите сделать родительским свой собственный маршрут, то его необходимо указать отдельно:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Первое определение Nested Route не будет работать так, как вы ожидаете, поскольку оно работает совершенно по-другому, используя компонент <Outlet/>
. Компонент <Outlet/>
используется для отображения дочерних маршрутов родительского маршрута. Компонент <Outlet/>
отображается только тогда, когда активен родительский маршрут. Это означает, что компонент <User/>
будет отображаться только при активном маршруте /users/:id
. Вот как это выглядит:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Конфигурация маршрутов остается прежней, но теперь элементы маршрута будут появляться внутри родительского элемента, в котором был объявлен <Outlet/>
.
Вкладывать элементы можно до бесконечности - только помните, что только листовые узлы станут собственными маршрутами. В данном примере создан только один маршрут /layer1/layer2
, и он отображается в виде трех вложенных div'ов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Если объявить функцию данных на родительском и дочернем маршрутах, то результат работы родительской функции данных будет передан в дочернюю функцию данных в качестве свойства data
аргумента, как это было описано в предыдущем разделе. Это работает, даже если маршрут не является прямым дочерним, поскольку по умолчанию каждый маршрут пересылает данные своего родителя.
Маршрутизатор с хэш-режимом¶
По умолчанию Solid Router использует location.pathname
в качестве пути маршрута. Вы можете просто переключиться в хэш-режим через свойство source
компонента <Router>
.
1 2 3 4 5 |
|
Маршрутизация на основе конфигурации¶
Для определения маршрутов необязательно использовать JSX. Для определения маршрутов можно также использовать объект config. Это удобно, когда вы хотите определить маршруты в отдельном файле и импортировать их в приложение, а затем передать их в useRoutes
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
|
Примитивы маршрутизатора¶
Solid Router предоставляет ряд примитивов, которые считывают контекст Router и Route.
useParams
¶
Получает реактивный объект типа store, содержащий текущие параметры маршрута, определенные в Route.
1 2 3 4 5 6 |
|
useNavigation
¶
Этот метод извлекает метод для императивной навигации. Он возвращает функцию navigate
, которая принимает путь и необязательный объект options. Объект options может содержать свойство replace
, чтобы заменить текущую запись истории вместо того, чтобы проталкивать новую.
1 2 3 4 5 |
|
Вот список доступных опций:
- resolve (boolean, по умолчанию
true
): преобразовать путь к текущему маршруту - replace (boolean, по умолчанию
false
): заменить запись в истории - scroll (boolean, по умолчанию
true
): прокрутка к верху после навигации - state (any, по умолчанию
undefined
): передавать пользовательское состояние в location.state
Примечание: Сериализация состояния осуществляется с использованием structured clone algorithm, который поддерживает не все типы объектов.
useLocation
¶
Извлекает реактивный объект location
, полезный для получения таких вещей, как pathname
, search
, hash
, state
и т. д.
1 2 3 4 5 |
|
useSearchParams
¶
Получает кортеж, содержащий реактивный объект для чтения параметров запроса текущего местоположения и метод для их обновления. Объект является прокси, поэтому для подписки на реактивные обновления необходимо получить доступ к свойствам. Обратите внимание, что значения будут строками, а имена свойств сохранят свой регистр.
Метод setter принимает объект, записи которого будут объединены в текущую строку запроса. Значения типа ''
, undefined
и null
будут удалять ключ из результирующей строки запроса. Обновления будут вести себя так же, как навигация, и сеттер принимает тот же необязательный второй параметр, что и navigate
, а автопрокрутка по умолчанию отключена.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
useIsRouting
¶
Получает сигнал, указывающий, находится ли маршрут в данный момент в состоянии перехода. Полезно для отображения состояния "застоялся/отложен", когда разрешение маршрута приостановлено во время параллельного рендеринга.
1 2 3 4 5 6 7 |
|
useRouteData
¶
Получает возвращаемое значение из функции data function.
1 2 3 4 5 |
|
1 2 3 4 5 |
|
useMatch
¶
Функция useMatch
принимает аксессор, возвращающий путь, и создает Memo, возвращающий информацию о совпадении, если текущий путь совпадает с предоставленным путем. Полезно для определения соответствия заданного пути текущему маршруту.
1 2 3 |
|
useRoutes
¶
Используется для определения маршрутов через объект конфигурации вместо JSX. См. раздел Маршрутизация на основе конфигурации.
useBeforeLeave
¶
Функция useBeforeLeave
принимает функцию, которая будет вызвана перед выходом из маршрута. Функция будет вызвана с:
from
(Location
): текущее местоположение (до изменения).to
(string | number
): путь, переданный для навигации.options
(NavigateOptions
): опции, передаваемые навигатору.preventDefault
(void function): вызов блокировки изменения маршрута.defaultPrevented
(readonly boolean): true, если все ранее вызванные обработчики оставления вызывали preventDefault().retry
(void function, force?: boolean ): вызов для повторного выполнения той же навигации, возможно, после согласования с пользователем. Передайте true, чтобы пропустить повторный запуск обработчиков ухода (т.е. принудительный переход без подтверждения).
Пример использования:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Более подробную информацию о Solid Router можно найти в репозитории Github здесь.