Как реализовать динамические сегменты с помощью useParams в React Router
На традиционном веб-сайте, когда пользователь нажимает на URL-адрес, браузер выполняет полностраничный запрос с сервера и направляет пользователя на новую страницу. Это называется статической маршрутизацией. Это очень полезно, если вам просто нужно перевести пользователя на новую страницу. Но с развитием веб-приложений возрастает потребность в том, чтобы страницы отображались на клиенте или загружались динамически.
Это включает в себя обновление определенных частей URL-адреса, называемых сегментами, а также отображение нового контента или обновление контента на той же странице без запроса с сервера или перезагрузки всей страницы. Это очень распространено и полезно в современных веб-приложениях. Оно обеспечивает рендеринг на стороне клиента, улучшает навигацию по веб-сайту и обеспечивает плавные переходы и анимацию (поскольку браузеру не требуется перезагрузка страницы с внешних серверов).
Это может в целом улучшить производительность веб-сайта и обеспечить удобство работы с пользователем. В этом уроке вы узнаете о динамических сегментах в React Router. Мы рассмотрим, что такое динамическая маршрутизация и чем она отличается от статической маршрутизации. Мы также расскажем, как использовать useParams для включения динамических сегментов и как установить путь при получении данных из API.
Наконец, мы создадим новый проект, который динамически отображает новый контент на той же странице, когда пользователь нажимает на боковую панель. К концу этого руководства вы сможете самостоятельно реализовывать динамические сегменты в своем приложении React.
Предварительные условия
Чтобы следовать инструкциям, вам потребуются базовые знания в следующих областях:
- React
- React-Router
- Tailwind CSS (необязательно)
Настройка проекта
Для начала создайте папку с именем dynamic-segment
и откройте ее в VS Code (или в любом редакторе кода):
Затем нажмите Ctrl +
(обратная кавычка), чтобы запустить терминал, как указано выше. Это позволит нам установить пакеты npm
, которые мы будем использовать в этом проекте.
Инсталляция
Теперь, когда наш проект настроен, давайте установим npm
пакеты, необходимые для запуска нашего проекта.
Установите React
React — это библиотека JavaScript для создания многократно используемых и интерактивных компонентов. Чтобы установить его, скопируйте и вставьте команду, предоставленную vite.js ниже.
npm create vite@latest
Затем просто следуйте инструкциям по установке, чтобы завершить процесс. После завершения установки папка node_modules
должна появиться в папке вашего проекта.
Установите React Router
React Router — это библиотека маршрутизации React для создания приложений маршрутизации на стороне клиента. Чтобы установить его, скопируйте и вставьте команду ниже и нажмите Enter.
npm i react-router-dom
Установить Feather Icon
Feather Icon — это небольшая, но красивая коллекция иконок с открытым исходным кодом размером 24x24. Она создан для добавления плоских значков в веб-приложения. Чтобы установить ее, вставьте команду ниже и нажмите Enter.
Установите Tailwind CSS
Tailwind — это многофункциональный CSS-фреймворк для создания красивых и компактных дизайнов веб-сайтов. Чтобы установить его, запустите команду на терминале ниже.
npm install -D tailwindcss postcss autoprefixer
Это создаст tailwind.config.js
файл. Затем сгенерируйте файлы postcss.config.js
с помощью команды ниже:
npx tailwindcss init -p
Затем настройте пути к шаблонам и добавьте пути ко всем файлам шаблонов в свой tailwind.config.js
файл. Затем нажмите ctrl + s
, чтобы сохранить.
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Затем удалите все стили CSS в ./src/index.css
файле и добавьте директивы @tailwind
для каждого слоя Tailwind.
@tailwind base;
@tailwind components;
@tailwind utilities;
Далее удалите папку assets
, файлы App.css
и App.jsx
из папки /src
. После этого настройте файл main.jsx
в качестве компонента маршрута, как показано ниже:
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css';
import {
RouterProvider,
createBrowserRouter,
createRoutesFromElements,
Route
} from 'react-router-dom';
const router = createBrowserRouter(
createRoutesFromElements(
<Route>
<Route path='/' element={<p className='text-blue-700'>Hello, world</p>}></Route>
</Route>
)
)
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
)
Затем выполните следующую команду в терминале, чтобы запустить приложение:
npm run dev
Ваше приложение должно выглядеть в вашем браузере следующим образом:
Маршрутизация на стороне клиента
В React Router навигация между атрибутом path
и свойством to
является относительной. Когда пользователь щелкает компонент <Link>
(тег <a>
), он переходит к указанному path
в компоненте маршрута и отображает соответствующий компонент.
Этот тип навигации называется маршрутизацией на стороне клиента, поскольку мы не отображаем страницы с сервера, а переходим от одного компонента к другому внутри приложения.
В приведенном ниже примере объясняется, как работает маршрутизация на стороне клиента:
⚠️ //main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css';
nt
import
{
RouterProvider,
createBrowserRouter,
createRoutesFromElements,
Route
} from 'react-router-dom';
import Book from './book';
import Bookshop from './bookshop';
const router = createBrowserRouter(
createRoutesFromElements(
<Route>
👉 <Route path='/' element={<Book />}></Route>
👉 <Route path='bookshop' element={<Bookshop />}></Route>
</Route>
)
)
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
)
Из приведенного выше примера кода мы импортировали два компонента Book
и Bookshop
и связали их через тег <a>
и компонент Route
в ./src/main.jsx
.
⚠️ //book.jsx
export default function Book() {
return (
<>
<main className="px-4">
<ul>
<ol>77 Ways get to more customers By: <i>Ubuy</i></ol>
<ol>Authenticity By: <i>Emanuel Rose</i> </ol>
<ol> Change Your thinking change your life By: <i>Brian Tracy</i></ol>
👉 <a href="bookshop" className="text-blue-600 inline-block px-4 underline">see bookshop</a>
{/* <a href="publisher/itemId" className="text-blue-600 underline">Publisher</a> */}
</ul>
</main>
</>
)
}
Атрибут href
принимает компонент bookshop
как относительный путь. Таким образом, щелчок по ссылке приведет вас к компоненту bookshop
.
⚠️ //bookshop.jsx
export default function Bookshop() {
return (
<div className="px-4">
<h1>list of book shops</h1>
<ul>
<li>Book Shop & Stationery</li>
<li>Simon books</li>
<li>Dynamic Book home</li>
</ul>
👉 <a href="/" className="text-blue-600 inline-block px-4 underline">Names of Books</a>
</div>
)
}
Компонент href=”/”
в bookstore
определяет индексный маршрут и должен вернуть вас обратно к домашним компонентам.
Ваше приложение должно выглядеть в браузере следующим образом: щелкните, чтобы перейти к компоненту книжного магазина.
Из вывода браузера выше вы заметите, как URL-адрес обновляется в адресной строке и отображается новый компонент.
Этот тип маршрутизации называется маршрутизацией на стороне клиента и обновляет путь URL-адреса только один раз при новом маршруте.
В следующем разделе я объясню, как можно обновлять определенный сегмент и динамически отображать контент.
Динамические сегменты
Динамический сегмент, как следует из названия, — это способ отрисовки нового компонента (UI) путем обновления определенного сегмента URL-адреса, называемого параметрами. Для этого вы используете хук useParams из react-router-dom
.
Это очень полезно в ситуациях, когда контент необходимо динамически отображать из определенного компонента или стороннего API.
Продолжая с того места, на котором мы остановились в коде, переходим к ./src/main.jsx
компоненту. Отредактируйте маршрут и добавьте :itemId
к нему в путь, как указано ниже:
⚠️ //main.jsx
<Route>
<Route path='/' element={<Book />}></Route>
<Route path='bookshop' element={<Bookshop />} />
👉 <Route path='publisher/:itemId' element={<Publisher />} />
</Route>
Обратите внимание, что :
в сегменте :itemId
URL означает динамический сегмент.
Затем создайте новый компонент ./src/publisher.jsx
и добавьте приведенный ниже код:
⚠️ //publisher.jsx
import { useParams } from "react-router-dom"
export default function Publisher() {
const { itemId } = useParams();
return (
<>
{
itemId ? (
<div>
<h1>Book publishing companies</h1>
<ul>
<ol>Penguin Random House</ol>
<ol>Scholastic</ol>
<ol>LPI Media</ol>
</ul>
</div>
) : (
<p>Page item is not present</p>
)
}
</>
)
}
Давайте поговорим о том, что делает этот код:
const { itemId } = useParams()
: здесь мы применяем деструктуризацию, чтобы получить параметры из URL-адреса в адресной строке. Благодаря этому мы можем визуализировать возвращаемый контент.itemId?():
: здесь мы условно отображаем список компаний-книжных магазинов, когда нажатая ссылка соответствует параметрам.
Затем в ./src/book
компоненте включите, publisher/itemId
как указано в теге <a>
ниже:
⚠️ //book.jsx
export default function Book() {
return (
<>
<main className="px-4">
<ul>
<ol>77 Ways get to more customers By: <i>Ubuy</i></ol>
<ol>Authenticity By: <i>Emanuel Rose</i> </ol>
<ol> Change Your thinking change your life By: <i>Brian Tracy</i></ol>
<a href="bookshop" className="text-blue-600 inline-block px-4 underline">see bookshop</a>
👉 <a href="publisher/itemId" className="text-blue-600 underline">Publisher</a>
</ul>
</main>
</>
)
}
Ваше приложение должно выглядеть в вашем браузере следующим образом:
Обратите внимание на обновление URL-адреса в адресной строке браузера.
Давайте посмотрим на другой пример.
В реальном приложении динамические сегменты в основном используются для динамического отображения контента, когда сегмент :itemId
cоответствует id
возвращаемому API.
Давайте посмотрим, как это работает. Во-первых, нам нужно решить, откуда мы будем получать наши данные. В этом случае создайте внешний объект JavaScript ./scr/books.js
, скопируйте и вставьте приведенный ниже код:
⚠️ //books.js
export default [
{ id: "1",
title: "The Great Gatsby",
author: "F. Scott Fitzgerald",
year: "1925",
description: "The Great Gatsby is a 1925 novel by American writer F. Scott Fitzgerald. Set in the Jazz Age on Long Island, near New York City, the novel depicts first-person narrator Nick Carraway's interactions with mysterious millionaire Jay Gatsby and Gatsby's obsession to reunite with his former lover, Daisy Buchanan."
},
{ id: "2",
title: "Pride and Prejudice",
author: "Jane Austen",
year: "1813",
description: "Pride and Prejudice is the second novel by English author Jane Austen, published in 1813. A novel of manners, it follows the character development of Elizabeth Bennet, the protagonist of the book"
},
{ id: "3",
title: "To Kill a Mockingbird",
author: "Harper Lee",
year: "1960",
description: "To Kill a Mockingbird is a novel by the American author Harper Lee. It was published in June 1960 and became instantly successful. In the United States"
},
{ id:"4",
title: "Beloved",
author: "Toni Morrison",
year: "1987",
description: "Beloved is a 1987 novel by American novelist Toni Morrison. Set in the period after the American Civil War, the novel tells the story of a dysfunctional family of formerly enslaved people whose Cincinnati home is haunted by a malevolent spirit"
}
]
Затем создайте новый компонент с именем ./src/FavBooks.jsx
и напишите в нем приведенный ниже код:
⚠️ //FavBooks.js
import { useParams } from 'react-router-dom';
import book from './book';
export default function FavBooks() {
const {bookId} = useParams()
👉 const newFavBook = book.find((book) => book.id === bookId)
if(!newFavBook){
return <p>{`This page doesn't contain fav Books`}</p>
}
return (
<>
<main>
{newFavBook && (
<>
<main>
<p>{`Title: ${newFavBook.title}`}</p>
<p>{`By: ${newFavBook.author}`}</p>
<p>{`Year: ${newFavBook.year}`}</p>
<p>{`Description: ${newFavBook.description}`}</p>
</main>
</>
)}
</main>
</>
)
}
Далее перейдите к ./src/book.jsx
компоненту и обновите код следующим образом:
import { Link } from 'react-router-dom';
import books from './book.js';
export default function Books() {
return (
<>
<div className='m-4'>
<p className="text-3xl">{`List of my favourite books`}</p>
</div>
<div className='m-4'>
{
books && books.map((book)=> (
<>
<ul>
<li>
<Link to={`newbooks/${book.id}`} className='text-blue-600 underline'>{book.title}</Link>
</li>
</ul>
</>
))
}
</div>
</>
)
}
Затем настройте path
для динамического сегмента компонента маршрута:
import Book from '../src/books';
import Bookshop from './bookshop';
import Publisher from './publisher';
👉 import FavBooks from './FavBooks';
const router = createBrowserRouter(
createRoutesFromElements(
<Route>
<Route path='/' element={<Book />}></Route>
<Route path='bookshop' element={<Bookshop />} />
<Route path='publisher/:itemId' element={<Publisher />} />
👉 <Route path='newbooks/:bookId' element={<FavBooks />} />
</Route>
)
)
Ваше приложение должно выглядеть в вашем браузере следующим образом:
Из вывода браузера параметры URL-адреса обновляются с использованием сегмента пути и значений идентификатора из объекта book.js
.
Попробуйте щелкнуть каждый заголовок и обратите внимание, как идентификатор объекта book.js
присутствует в URL-адресе.
Когда пользователь щелкает ссылку, на новой странице отображается новый пользовательский интерфейс. Но бывают случаи, когда вам может потребоваться отобразить содержимое API на той же странице, что и элементы списка, чтобы содержимое не открывалось на новой странице. Для этого нам нужно реализовать вложенную маршрутизацию.
Вложенная маршрутизация
Вложенная маршрутизация позволяет вкладывать маршруты для рендеринга новых компонентов на одной странице для упрощения навигации и быстрого взаимодействия с элементом. Вложенные маршруты позволяют перечисленным элементам функционировать как вкладки. При нажатии на любую вкладку отображается содержимое, соответствующее соответствующей вкладке.
Теперь давайте посмотрим, как преобразовать наше небольшое приложение во вложенный маршрут.
Чтобы перейти к ./src/main
компоненту и создать вложенный маршрут, выполните следующие действия:
const router = createBrowserRouter(
createRoutesFromElements(
<Route>
<Route path='/' element={<Book />} >
👉 <Route path='newbooks/:bookId' element={<FavBooks />} />
</Route>
<Route path='bookshop' element={<Bookshop />} />
<Route path='publisher/:itemId' element={<Publisher />}>
</Route>
</Route>
)
)
По сути, мы вкладываем компонент FavBook
в компонент Book
как его прямой дочерний элемент, поэтому содержимое будет отображаться под ним.
Затем создайте тег div
и визуализируйте компонент outlet
. Это мы сообщаем React маршрутизатору, где визуализировать новый вложенный маршрут.
return (
<>
<div className='m-4'>
<p className="text-3xl">{`List of my favourite books`}</p>
</div>
👉 <section className='flex'>
<div className='m-4'>
{
books && books.map((book)=> (
<>
<ul>
<li>
<Link to={`newbooks/${book.id}`} className='text-blue-600 underline'>{book.title}</Link>
</li>
</ul>
</>
))
}
</div>
<div className='w-[70%]'>
👉 <Outlet />
</div>
</section>
</>
)
Обратите внимание, что для визуализации рядом вложенного компонента FavBook
и тег outlet
, и тег списка книг вложены в тег раздела, и применяется стиль гибкого отображения.
Ваш код должен выглядеть в вашем браузере следующим образом:
Из вывода браузера вы можете видеть, что каждый элемент в списке функционирует как вкладка, и при нажатии на них отображается содержимое API.
Вы узнали, как создать динамический сегмент. В следующем разделе мы создадим проект, который поможет еще больше закрепить полученные знания.
Проект: построить художественную галерею
В этом проекте мы собираемся создать приложение художественной галереи, содержащее список скульптур и произведений искусства из разных стран. Это поможет вам закрепить ранее изученные понятия.
Мы собираемся реализовать следующие функции:
- Маршрутизация на стороне клиента
- Активные ссылки
- Динамические сегменты
- Вложенные маршруты
Ниже представлен краткий обзор того, как будет выглядеть проект.
Обзор проекта
Вот полный предварительный просмотр нашего проекта после завершения. Вы можете скачать исходный код GitHub здесь.
Структура папок
Вот как должна выглядеть структура папок проекта:
📂src
📂apis
├──data.js
📂components
├──AsideBar.jsx
├──Content.jsx
├──Navbar.jsx
📂pages
├──home.jsx
├──index.css
├──main.jsx
├──index.html
Как настроить домашнюю страницу
Чтобы настроить домашнюю страницу, создайте домашний компонент ./src/pages/home.jsx
и добавьте приведенный ниже код:
├──home.jsx
export default function Home() {
return (
<>
<main className="">
<section>
<p className="text-orange-600">Hello World</p>
</section>
</main>
</>
)
}
Далее переходим к main.jsx
компоненту. Если у вас его еще нет, создайте его, как ./src/main.jsx.
затем настройте маршрут следующим образом:
├──main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css';
import {
RouterProvider,
createBrowserRouter,
createRoutesFromElements,
Route
} from 'react-router-dom';
import Home from './pages/home';
const router = createBrowserRouter(
createRoutesFromElements(
<Route path='/' element={<Home />}>
</Route>
)
)
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
)
Затем введите, npm run dev
чтобы запустить приложение.
Ваше приложение должно выглядеть в вашем браузере следующим образом:
Как создать и стилизовать панель навигации
Теперь, когда у нас настроены компоненты дома и маршрута, давайте создадим компонент навигационной панели, который является верхним компонентом в нашем приложении.
Создайте компонент ./src/components/navbar.jsx
и добавьте приведенный ниже код:
├──navbar.jsx
import { Activity, Search } from "react-feather";
export default function Navbar() {
return (
<>
<main className="">
<header>
<nav className="flex justify-between bg-slate-200 rounded-3xl py-2">
{/* logo */}
<div className="">
<Activity className="inline-block ml-10 mr-2 text-orange-500" />
<p className="inline-block text-xl">{`Arts & Culture`}</p>
</div>
{/* Navlinks */}
<div className="bg-white rounded-3xl py-1 px-2 mr-5">
<Search className="inline-block mr-1 text-slate-500"/>
<input type="search" id="site-search" name="q" placeholder="Search anything" className="bg-transparent outline-none text-slate-800"/>
</div>
</nav>
</header>
</main>
</>
)
}
Судя по приведенному выше коду, панель навигации разделена между логотипом и панелью поиска.
- Логотип: мы импортируем значки действий как компонент из feather icons и применяем некоторые CSS-классы Tailwind для его стилизации. Значок настроен как
inline-block
, мы можем применить к нему пространство. Мы применяемml-10
иmr-2
, которые имеют поля слева2.5rem
и справа0.5rem
оранжевого цвета (text-orange-500
). - Поиск: для панели поиска мы также импортировали ее из feather icons как компонент и применили следующий стиль:
inline-block mr-1 text-slate-500
. Если вам сложно понять CSS-классы Tailwind, вы можете прочитать о них больше в документации здесь.
Чтобы расположить логотип и панель поиска рядом, мы установили родительский заголовок для отображения гибкого содержимого и выравнивания содержимого пробела между ними, чтобы добавить пространство между логотипом и панелью поиска.
Затем добавьте панель навигации к маршруту следующим образом:
├──main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
import {
RouterProvider,
createBrowserRouter,
createRoutesFromElements,
Route
} from "react-router-dom"
👉 import Navbar from './components/Navbar'
import Home from './pages/home'
const router = createBrowserRouter(
createRoutesFromElements(
<Route path='/' element={<Home />}>
👉 <Route path='/' element={<Navbar />} />
</Route>
)
)
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
)
В приведенном выше коде компонент Navbar
вложен в компоненты Home
. Это означает, что нам нужно использовать компонент Outlet
для рендеринга компонента Navbar
.
Затем перейдите к компоненту ./src/page/home
, импортируйте и замените <p>
компонентом Outlet, как показано ниже:
├──home.jsx
👉 import { Outlet } from "react-router-dom";
export default function Home() {
return (
<>
<main className="">
<section>
👉 <Outlet />
</section>
</main>
</>
)
}
Ваше приложение должно выглядеть в вашем браузере следующим образом:
Как создать AsideBar
AsideBar
один из наиболее важных компонентов нашего приложения. Здесь будут отображаться названия культур. Этот компонент функционирует как вкладка, и когда пользователь щелкает по нему, он отображает более подробную информацию о культуре, на которую он нажал.
Создайте новый компонент как ./src/components/AsideBar.jsx
и напишите код ниже:
├──AsideBar.jsx
import { NavLink } from "react-router-dom"
import data from "../apis/data"
export default function AsideBar() {
const activeStyle = ({isActive}) => {
return {
backgroundColor : isActive ? "rgb(154 52 18)" : "",
color : isActive ? "rgb(255 247 237)" : "",
}
}
return (
<>
<main className="w-[100%] mt-[2em]">
<section className="w-[100%]">
<aside className="w-[fit-content] bg-slate-200 rounded-xl">
{
data.map((data)=>(
<ul key={data.id}>
<li className="">
<NavLink className="w-[100%] py-3 px-2 inline-block text-slate-800 hover:bg-orange-200 transition-all whitespace-nowrap border-y-4 " to={`content/${data.id}`} style={activeStyle}>
{data.type}
</NavLink>
</li>
</ul>
))
}
</aside>
</section>
</main>
</>
)
}
В приведенном выше примере кода наш код разделен на две части: компонент data
и NavLink
компонент.
- Data: мы импортировали данные из
./src/apis/data.js
, сопоставляем каждый массив объектов и возвращаем ихdata.type
в качестве имен файловAsideBar
. - NavLink: возвращаемые данные
data.js
отображаются непосредственно вNavLink
компоненте. ВNavLink
компоненте указаны два реквизита:style
иto
. Первый получилactiveStyle
объект, указывающий к какому стилю следует применить,NavLink
когда он активен. В параметреto
content/${to
data.idto={
}}
мы передаемdata.id
как сегмент, соответствующий компонентамpath
контента (подробнее об этом в следующем разделе). Это позволяет контенту динамически отображаться при нажатииNavLink
.
Затем перейдите к домашнему компоненту и отрендерите AsideBar
как показано ниже:
├──home.jsx
import { Outlet } from "react-router-dom";
👉 import AsideBar from "../components/AsideBar";
export default function Home() {
return (
<>
👉 <main className="w-[80%] mt-[2em] mx-auto">
<section>
<Outlet />
</section>
<section>
<aside>
👉 <AsideBar />
</aside>
</section>
</main>
</>
)
}
Ваше приложение должно выглядеть в вашем браузере следующим образом:
При взаимодействии с Asidebar
, вы, возможно, заметили, что страница прерывается каждый раз, когда вы нажимаете на ссылку. Это связано с тем, что компонент контента еще не определен. Итак, давайте создадим его.
Как создать компонент контента
Компонент контента отображает контент, связанный с конкретной ссылкой, по которой был выполнен щелчок.
Создайте новый компонент ./src/components/Content.jsx
и добавьте приведенный ниже код:
├──Content.jsx
import { Link, useParams } from "react-router-dom";
import data from "../apis/data.js";
import { WifiOff } from "react-feather";
export default function Content() {
const {contentId} = useParams()
const newData = data.find((data)=> data.id.toString() === contentId)
if(!contentId){
return (
<main className="translate-x-44 translate-y-44">
<div className="">
<WifiOff className="text-slate-400 text-center translate-x-48"/>
<p className="text-slate-400">{`Content can't be accessed! click the left nav to reload`}</p>
</div>
</main>
)
}
return (
<>
<main className="w-[80%] mx-auto mt-8">
<section >
{
newData && (
<>
{/* Image Over */}
<aside className="h-[6em] w-[100%]">
<div className="h-[100%] w-[100%]">
<img src={newData.imgHeaders} alt="" className="h-[100%] w-[100%] object-cover rounded-xl"/>
</div>
</aside>
{/* Details */}
<section className="flex gap-6">
<aside className="w-[50%]">
<div>
<p className="bg-orange-500 w-[fit-content] rounded-xl mt-4 py-1 px-2 font-bold">{newData.catagories}</p>
<h1 className="font-light text-4xl my-7">{newData.type}</h1>
<p className="font-bold mb-4 text-2xl">{newData.region}</p>
</div>
<div>
<p className="font-light">{newData.history}</p>
</div>
<div className="mt-4">
<span>{`Learn more from`}</span>
<Link to={newData.britannicaLink} target="_blank" className="text-orange-500 py-2 px-2 rounded-md inline mt-4 hover:underline hover:text-black">britannica</Link>
</div>
</aside>
{/* Image Cover */}
<aside className="w-[50%]">
<div>
<img src={newData.imgCover} alt="" className="rounded-3xl mt-10"/>
</div>
</aside>
</section>
</>
)
}
</section>
</main>
</>
)
}
Код выше делает следующее:
- useParams: мы используем хук useParams() для возврата пар ключ-значение динамического сегмента
content/:contentId
указанного в маршруте. - newData: с помощью метода массива find() возвращается первый элемент массива объектов, если условие истинно, в противном случае возвращается
undefined
. - if(!contentId): здесь мы проверяем, не соответствует ли элемент
contentId
или еще не отрисован – тогда предоставленный элемент внутри функции должен запуститься. Это очень полезно для проверки ошибок и в ситуациях, когда контент недоступен. - newData &&: здесь мы сопоставляем возвращаемый объект данных и отображаем содержимое API, как только содержимое загружается. Каждое свойство объекта анализируется в элемент для отображения как содержимого.
Затем перейдите к домашнему компоненту и визуализируйте компонент контента, как показано ниже.
├──home.jsx
import { Outlet } from "react-router-dom";
import AsideBar from "../components/AsideBar";
👉 import Content from "../components/Content";
export default function Home() {
return (
<>
<main className="w-[80%] mt-[2em] mx-auto">
<section>
<Outlet />
</section>
<section className="flex">
<aside>
<AsideBar />
</aside>
<aside>
👉 <Content />
</aside>
</section>
</main>
</>
)
}
Далее настройте маршрут к динамическому сегменту:
├──home.jsx
import Home from './pages/home';
import Navbar from './components/navbar';
👉 import Content from './components/Content';
const router = createBrowserRouter(
createRoutesFromElements(
<Route path='/' element={<Home />}>
<Route path='/' element={<Navbar />}>
👉 <Route path='content/:contentId' element={<Content />} />
</Route>
</Route>
)
)
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>,
)
Ваше приложение должно выглядеть в вашем браузере примерно так:
Нажатие на значок Asidebar
загрузит контент из API и отобразит его на той же странице, что и файл Asidebar
.
Итог
В этом уроке мы узнали о динамических сегментах в React Router. Мы поговорили о том, что такое динамический маршрутизатор и чем он отличается от статической маршрутизации. Вы также узнали, как использовать перехватчик useParams
для включения динамических сегментов, а также как задать путь при получении данных из API.
Затем мы создали новый проект, который динамически отображал новый контент на той же странице, когда пользователь нажимает на боковую панель.
Вы можете развивать этот проект дальше и сделать его своим, реализовав дополнительные функции.