React Router, версия 6. Часть 4 из 4
23.12.2021
Теги: Frontend • JavaScript • React.js • Web-разработка • Маршрутизация • Модуль
useSearchParams
Хук useSearchParams предназначен для чтения и изменения строки запроса в URL для текущего маршрута. По аналогии с хуком useState возвращает значение и функцию для изменения этого значения. Значение — это объект URLSearchParams, у которого множество методов для работы с GET-параметрами (get, set, getAll, has, append, delete, …), подробнее здесь.
const [searchParams, setSearchParams] = useSearchParams() for (let entry of searchParams.entries()) { console.log(entry[0] + '=' + entry[1]) } setSearchParams({hello: 'world'})
Давайте создадим две страницы PageOne и PageTwo, добавим ссылки на них в главное меню. На первой странице установим параметры запроса, а на второй — прочитаем эти параметры.
import { useNavigate, createSearchParams } from 'react-router-dom' const PageOne = () => { const navigate = useNavigate() const params = { from: 'OnePage', now: Date.now().toString() } const search = '?' + createSearchParams(params) const gotoPageTwo = () => { navigate({ pathname: '/page-two', search: search, }) } return ( <> <h1>Page One</h1> <button onClick={gotoPageTwo}>Go to Page Two</button> </> ) } export default PageOne
import { useSearchParams } from 'react-router-dom' const PageTwo = () => { const [searchParams, setSearchParams] = useSearchParams() const params = [] const search = {} for (let entry of searchParams.entries()) { params.push(entry[0] + '=' + entry[1]) search[entry[0]] = entry[1] } const appendParam = () => { setSearchParams({...search, rand: Math.random()}) } return ( <> <h1>Page Two</h1> <ul> {params.map(item => <li key={item}>{item}</li>)} </ul> <button onClick={appendParam}>Append param</button> </> ) } export default PageTwo
Исходные коды приложения здесь, директория 5.
Вложенные роуты
Мы уже работали с вложенными роутами — все роуты у нас вложены в <Route path="/">, кроме того, есть вложенные роуты для Blog и Service. Давайте добавим две вложенные страницы для About — это будут Company и Out team.
const Company = () => { return <h1>Company</h1> } export default Company
const OurTeam = () => { return <h1>Our team</h1> } export default OurTeam
import { Link, Route, Routes } from 'react-router-dom' import Company from './Company.js' import OurTeam from './OurTeam.js' const About = () => { return ( <> <h1>About page</h1> <ul> <li><Link to="company">Company</Link></li> <li><Link to="our-team">Our team</Link></li> </ul> <Routes> <Route path="company" element={<Company />} /> <Route path="our-team" element={<OurTeam />} /> </Routes> </> ) } export default About
Внесем изменения в компонент App.js:
function App() { return ( <AuthProvider> <Routes> <Route path="/" element={<AppLayout />}> <Route index element={<Home />} /> .......... <Route path="about/*" element={<About />} /> .......... <Route path="*" element={<NotFound />} /> </Route> </Routes> </AuthProvider> ) }
Звездочка в атрибуте path означает, что что по маршрутам about/company и about/our-team будет отрабатывать компонент About. Но внутри About может быть еще один компонент Routes, который определяет маршруты относительно about. Хотя так можно делать, но лучше вынести вложенные маршруты в компонент App — чтобы все они были в одном месте.
import { Link, Outlet } from 'react-router-dom' const About = () => { return ( <> <h1>About page</h1> <ul> <li><Link to="company">Company</Link></li> <li><Link to="our-team">Our team</Link></li> </ul> <Outlet /> </> ) } export default About
function App() { return ( <AuthProvider> <Routes> <Route path="/" element={<AppLayout />}> <Route index element={<Home />} /> .......... <Route path="about" element={<About />}> <Route path="company" element={<Company />} /> <Route path="our-team" element={<OurTeam />} /> </Route> .......... <Route path="*" element={<NotFound />} /> </Route> </Routes> </AuthProvider> ) }
Исходные коды приложения здесь (директория app), демо-сайт здесь.
useRoutes
Компонент Routes является оберткой над useRoutes, два фрагмента кода ниже эквивалентны.
function App() { return ( <Routes> <Route path="/" element={<AppLayout />}> <Route index element={<Home />} /> <Route path="about" element={<About />} /> <Route path="*" element={<NotFound />} /> </Route> </Routes> ) }
function App() { const element = useRoutes([ { path: '/', element: <AppLayout />, children: [ { index: true, element: <Home /> }, { path: 'about', element: <About /> }, { path: '*', element: <NotFound /> }, ] }, ]) return element }
Атрибут basename
Если приложение развернуто в подкаталоге на сервере, необходимо использовать атрибут basename для BrowserRouter.
import React from 'react' import ReactDOM from 'react-dom' import { BrowserRouter } from 'react-router-dom' import './index.css' import App from './App.js' ReactDOM.render( <React.StrictMode> <BrowserRouter basename="/react-router-app"> <App /> </BrowserRouter> </React.StrictMode>, document.getElementById('root') )
Дополнительно
Отличный мини-курс от Михаила Непомнящего на YouTube:
- Базовый роутинг React-приложения
- Общая разметка и компонент Outlet
- Компонент NavLink и его кастомизация
- Параметры в ссылках
- Работа с историей, локацией и приватными роутами
- Параметры поиска
- Вложенный роутинг
Поиск: Frontend • JavaScript • React.js • Web-разработка • Маршрутизация • Модуль