React Router, версия 6. Часть 4 из 4

23.12.2021

Теги: FrontendJavaScriptReact.jsWeb-разработкаМаршрутизацияМодуль

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:

Поиск: Frontend • JavaScript • React.js • Web-разработка • Маршрутизация • Модуль

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.