🙈
React
  • 🧑‍💻Full-Stack Web Developer
  • 📚Теорія
    • 1️⃣Введення в React
      • Веб-застосунки
      • Бібліотека React
      • Інструменти
      • Створення і клонування своєї збірки React на базі Create React App
      • Елементи в React
      • JSX
      • Компоненти
      • Рендер за умовою
      • Колекції
    • 2️⃣Стилізація
      • Вбудовані стилі
      • Ванільний CSS
      • CSS модулі
      • Стилізовані компоненти
      • Нормалізація стилів
    • 3️⃣Події та стан
    • 4️⃣Форми
      • Formik
      • Yup валідація форм Formik
    • 5️⃣Життєвий цикл
    • 6️⃣HTTP-запити
    • 7️⃣React-хуки
    • 8️⃣Контекст та рефи
    • 9️⃣Маршрутизація
      • Маршрутизація
      • Компонент <BrowserRouter>
      • Компоненти <Route> та <Routes>
      • Компоненти <Link> та <NavLink>
      • URL-параметри
      • Вкладені маршрути
      • Індексні маршрути
      • Програмна навігація
      • Рядок запиту
      • Обʼєкт місцезнаходження
      • Розподілення коду
    • 🔟Redux Toolkit
      • Управління станом
    • 🕚Асинхронний Redux
    • Бібліотека Redux Persist для роботи з localstorage
    • Помилка non-serializable value і її виправлення
    • переключення теми
    • 👷Практика
  • Про мене
    • Про мене
Powered by GitBook
On this page
  1. Теорія
  2. Маршрутизація

Індексні маршрути

На більшості інтернет-сайтів певна частина інтерфейсу лишається незмінно. Наприклад шапка, підвал, бокове меню тощо. А при навігації по сайту змінюється лише вміст головного контейнера.

Немає сенсу на кожній сторінці дублювати цю розмітку. Можна зробити спільну обгортку із компонентів, які не змінюються, а при навігації по сайту змінювати тільки головний вміст. Для цього використовують прийом «shared layout».

src/components/App.jsx
// Import libraries and components

export const App = () => {
  return (
    <Container>
      <Header>
        <Logo>
          <span role="img" aria-label="logo icon">
            🙈
          </span>
          Monkey Studio
        </Logo>
        <nav>
           <Link to="/">Home</Link>
           <Link to="/about">About</Link>
           <Link to="/reviews">Reviews</Link>
           <Link to="/works">Works</Link>
        </nav>
      </Header>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />}>
           <Route path="team" element={<Team />} />
           <Route path="mission" element={<Mission />} />
           <Route path="founders" element={<Founders />} />
           <Route path="partners" element={<Partners />} />
        </Route>
        <Route path="/reviews" element={<Reviews />} />
        <Route path="/works" element={<Works />} />
        <Route path="/works/:workId" element={<WorkDetails />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </Container>
  );
};

У прикладі вище, головне меню навігації зверстано у файлі App.jsx. При нарощенні проєкту, стилізаційні елементи сильно перенавантажуватимуть App.jsx. Прийнято у файлі App.jsx прописувати тільки правила маршрутизації, без зайвого контенту, а всі стилізаційні компоненти та верстання незмінного блоку виносити в окремі блоки.

Тож, винесемо розмітку і стилі незмінної обгортки в окремий компонент <SharedLayout>. Там де ми плануємо рендерити змінну частину сайту в залежності маршруту на якому перебуваємо - вказуємо компонент <Outlet>.

src/components/SharedLayout.jsx
// Import libraries and components
import { Outlet } from "react-router-dom";

export const SharedLayout = () => {
  return (
    <Container>
      <Header>
        <Logo>
          <span role="img" aria-label="logo icon">
            🙈
          </span>
          Monkey Studio
        </Logo>
        <nav>
           <Link to="/">Home</Link>
           <Link to="/about">About</Link>
           <Link to="/reviews">Reviews</Link>
           <Link to="/works">Works</Link>
        </nav>
      </Header>
      <Outlet />
    </Container>
  );
};

Після цього потрібно використати компонент <SharedLayout> в компоненті <App>. Пропишемо так, щоб він рендерився на всіх маршрутах вкажемо його маршрут path="/". Вкладемо у нього всі інші маршрути АЛЕ маршрути пропишемо відносно батьківського Shared Layout - тобто prop path без символу /.

src/components/App.jsx
// Import libraries and components
import { SharedLayout } from "path/to/components/SharedLayout";

export const App = () => {
  return (
    <Routes>
      <Route path="/" element={<SharedLayout />}>
        <Route path="about" element={<About />}>
           <Route path="team" element={<Team />} />
           <Route path="mission" element={<Mission />} />
           <Route path="founders" element={<Founders />} />
           <Route path="partners" element={<Partners />} />
        </Route>
        <Route path="reviews" element={<Reviews />} />
        <Route path="works" element={<Works />} />
        <Route path="works/:workId" element={<WorkDetails />} />
        <Route path="*" element={<NotFound />} />
      </Route>
    </Routes>
  );
};

Тут видно, що за базовим маршрутом path="/" тепер рендериться тільки компонент <SharedLayout> без <Home>. Хоча за іншими вкладеними маршрутами рендериться як <SharedLayout>, так і той компонент у якого збігається path зі значенням в адресному рядку. Тобто за маршрутом path="about" зрендериться компонент <SharedLayout> і <About>.

Щоб виправити цей ньюанс і за базовим маршрутом рендерити <Home> компонент за тим же маршрутом необхідно створити індексний маршрут.

src/components/App.jsx
// Import libraries and components
import { SharedLayout } from "path/to/components/SharedLayout";

export const App = () => {
  return (
    <Routes>
      <Route path="/" element={<SharedLayout />}>
        <Route index element={<Home />} />
        <Route path="about" element={<About />}>
           <Route path="team" element={<Team />} />
           <Route path="mission" element={<Mission />} />
           <Route path="founders" element={<Founders />} />
           <Route path="partners" element={<Partners />} />
        </Route>
        <Route path="reviews" element={<Reviews />} />
        <Route path="works" element={<Works />} />
        <Route path="works/:workId" element={<WorkDetails />} />
        <Route path="*" element={<NotFound />} />
      </Route>
    </Routes>
  );
};

Індексним може бути лише вкладений маршрут. В його <Route> не вказують prop path, тому що він збігається зі значенням path батька. Замість цього передають спеціальний prop index, який вказує бібліотеці React Router, що цей маршрут треба відрендерити на ту ж адресу, що і його батько.

Індексних маршрутів може бути довільна кількість залежно від поставленого завдання. Наприклад, у панелі адміністратора можна рендерити інший інтерфейс і відповідно підключити інший <SharedLayout>.

src/components/App.jsx
// Import libraries and components
import { SharedLayout } from "path/to/components/SharedLayout";

export const App = () => {
  return (
    <Routes>
      <Route path="/" element={<SharedLayout />}>
        <Route index element={<Home />} />
        <Route path="about" element={<About />}>
           <Route path="team" element={<Team />} />
           <Route path="mission" element={<Mission />} />
           <Route path="founders" element={<Founders />} />
           <Route path="partners" element={<Partners />} />
        </Route>
        <Route path="reviews" element={<Reviews />} />
        <Route path="works" element={<Works />} />
        <Route path="works/:workId" element={<WorkDetails />} />
        <Route path="*" element={<NotFound />} />
      </Route>
      <Route path="/admin" element={<AdminLayout />}>
         <Route index element={<Dashboard />} />
         <Route path="sales" element={<Sales />} />
         <Route path="customers" element={<Customers />} />
      </Route>
    </Routes>
  );
};

PreviousВкладені маршрутиNextПрограмна навігація

Last updated 1 year ago

Нижче наведено живий приклад на маршрутизацію із SharedLayout. Проглянути код можна .

📚
9️⃣
тут