DevGang
Авторизоваться

Как реализовать динамические сегменты с помощью 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/${todata.id to={} мы передаем 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.

Затем мы создали новый проект, который динамически отображал новый контент на той же странице, когда пользователь нажимает на боковую панель.

Вы можете развивать этот проект дальше и сделать его своим, реализовав дополнительные функции.

Источник:

#React
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу