Lekce 11. - Jak zpracovat směrování v Reactu pomocí knihovny React Router

16.04.2021 Programování #react #programování

V této části se naučíme, jak spravovat cestu v naší aplikaci todos. Stejnou logiku pak můžeme použít na jakýkoli projekt React, se kterým pracujeme.


React, jak víme, je jednostránková aplikace (SPA). K vykreslení pohledu používáme jeden index.html soubor (ve složce public).  Někdy bychom ale chtěli mít pocit vícestránkové aplikace a mít možnost přejít na jiné stránky. Tady přichází na řadu směrování - routing.

Instalace

Začneme instalací react-router-dom v našem projektu.

Přejděte k terminálu a nainstalujte do svého projektu router React (v našem případě projekt todos).

npm install react-router-dom@5.2.0

Tato knihovna nám poskytuje všechny nástroje a komponenty, které potřebujeme k implementaci směrování v naší aplikaci React. U aplikace React native (mobile) byste místo toho nainstalovali native-router-router. V nové verzi 6 již níže uvedený kód není funkční, proto se při instalaci knihovny používá definice verze @5.2.0

Zastavme se na chvíli a přemýšlejme, co budeme dělat.

Chceme vytvořit různé pohledy (nebo „stránky“), které pro nás budou router zpracovávat. Obsah nebo domovská stránka, stránka s informacemi o chybě a stránka s chybami.

První věcí, kterou chceme udělat při vytváření směrování pomocí React Router, je zabalit komponentu nejvyšší úrovně, v našem případě prvek < todocontainer > do routeru.

Zde jsme představili naši první komponentu routeru, BrowserRouter.

Takže v souboru index.js importujte komponentu z modulu react-router-dom.

import { BrowserRouter } from "react-router-dom"

 
Pak zabalte aplikaci kontejneru takto:

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <TodoContainer />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
)

 

Pamatujte, že obal StrictMode již máme vytvořený. Bez ohledu na to, zda používáte striktní režim, zajistěte zabalení nadřazené aplikace komponentou Router.

Můžete také chtít použít alias, abyste jej reprezentovali takto:

import { BrowserRouter as Router } from "react-router-dom"

 

Pak použijte alias podobný render, takže:

ReactDOM.render(
  <React.StrictMode>
    <Router>
      <TodoContainer />
    </Router>
  </React.StrictMode>,
  document.getElementById("root")
)

Uložte soubor.

Co je přesně BrowserRouter?

Jedná se o typ směrovače, který používá rozhraní API historie HTML5 k udržení synchronizace adresy URL se zobrazením. U tohoto routeru jste si jisti, že budete mít v adresním řádku prohlížeče čistou adresu URL.

Něco takového:

http://yourapp.com/about

Stejně jako tento typ máme také HashRouter. Ale zde ukládá aktuální umístění do hash části adresy URL. Adresa URL, kterou sem dostanete, není tak čistá. Něco takového:

http://yourapp.com/#/about

Většinu času budete používat BrowserRouter.

V současné době máme v komponentě TodoContainer vykreslen aktuální pohled. Ve stejné komponentě můžeme dynamicky vykreslit jiný pohled na základě cesty, která jim byla předána.

K tomu využíváme další důležité komponenty z react-router-dom. Komponenty Switch Route.

Jděte do souboru TodoContainer.js a importujte je takto:

import { Route, Switch } from "react-router-dom"

Pak zabalte prvky JSX do příkazu return komponentou Route. A pak předejte vlastnost path směřující na indexovou stránku „/“.

return (
  <Route path="/">
    <div className="container">
      <div className="inner">
        <Header />
        <InputTodo addTodoProps={addTodoItem} />
        <TodosList
          todos={todos}
          handleChangeProps={handleChange}
          deleteTodoProps={delTodo}
          setUpdate={setUpdate}
        />
      </div>
    </div>
  </Route>
)

Uložte soubor.

Cesta

Komponenta Route je zodpovědná za vykreslení uživatelského rozhraní, když jeho cesta odpovídá aktuální adrese URL. Jak vidíte v kódu, path ukazuje na domovskou stránku. Takže vykresluje prvky JSX.

Tato vlastnost path se používá k identifikaci části adresy URL, které by měl směrovač odpovídat. Pokud se zobrazení změní, nemusí již odpovídat cestě. V takovém případě vykreslí NULL.

Poznámka: Shoda zde odkazuje na začátek adresy URL. V tomto případě bude cesta trasy „/“ ve výše uvedeném kódu vždy odpovídat jakékoli adrese URL. To je důvod, proč i když přejdete na http: // localhost: 3000 / about , vaše aplikace bude stále vykreslovat uživatelské rozhraní. Můžete to vyřešit přidáním exact k trase takto:

<Route exact path="/">

Použití vlastnosti exact na trase z toho dělá path exkluzivitu .

K vyřešení tohoto problému můžete také použít komponentu Switch.

Normálně byste komponentu Route neměli používat mimo Switch. V tuto chvíli nevíte, co to je. Pojďme to tedy krátce probrat.

Switch

Již jsme zmínili, že vytvoříme více pohledů, tj. stránek. Trasu indexovací stránky již máme, jak je vidět v return v souboru TodoContainer.js.

Vytvořme další dvě stránky. Stránka O aplikaci a chybě.

Přejděte do adresáře projektu a vytvořte složku pages. Na základě struktury našeho projektu přejdeme do složky src/functionBased a vytvoříme. V našem případě ve složce src/.

Ve složce pages vytvořte dva soubory komponent. About.js NotMatch.js.

Pojďme vykreslit jednoduchou funkční komponentu ve dvou souborech. Pro About.js, přidejte toto:

import React from "react"

const About = () => {
  return <div>hello from about page</div>
}
export default About

NotMatch.js vypadá takto:

import React from "react"

const NotMatch = () => {
  return (
    <div>
      <h3>No match for this page</h3>
    </div>
  )
}
export default NotMatch

Uložte soubory a importujte je do souboru TodoContainer.js.

import About from "../pages/About"
import NotMatch from "../pages/NotMatch"

Poté aktualizujte return tak, aby zahrnovalo tyto nové součásti. Všimněte si, že vše zabalíme fragmentem React. Měli byste vědět proč. Nemůžete vykreslit více souborů JSX, pokud je nezabalíte do jednoho prvku nebo nepoužijete fragment React.

return (
  <>
    <Route exact path="/">
      ...
    </Route>
    <Route path="/about">
      <About />
    </Route>
    <Route path="*">
      <NotMatch />
    </Route>
  </>
)

Pokud soubor uložíte a přejdete na neexistující stránku /about. Chybová komponenta se na těchto stránkách vždy vykreslí. Aby bylo jasno, můžete dočasně odebrat exact z cesty indexu a uložit soubor.

Nyní zkontrolujte svou aplikaci a znovu procházejte.

V aktuálním nastavení je něco běžné. Nyní vidíme uživatelské rozhraní indexu a uživatelské stránky chyby v každém zobrazení.

Z předchozí diskuse víme, že trasa path indexu „/“ bude vždy odpovídat adrese URL. Takže se vykresluje na každé stránce.

A co stránka NotMatch?

Stejná věc. A < Route path="*” > vždy odpovídá. Takže se také vykreslí.

Cestu indexu jsme vyřešili přidáním vlastnosti exact k její cestě. Abychom vyřešili cestu NotMatch, přidáme Switch.

Switch je další komponenta, react-router-dom, která nám pomáhá vykreslit uživatelské rozhraní. Zabalí všechny vaše < Route > prvky, prohlédne je a poté vykreslí prvního potomka, jehož cesta odpovídá aktuální adrese URL.

Podívejme se, jak to funguje.

Zabalte všechna < Route > s komponentou < Switch >.

return (
  <Switch>
    <Route exact path="/">
      ...
    </Route>
    <Route path="/about">
      <About />
    </Route>
    <Route path="*">
      <NotMatch />
    </Route>
  </Switch>
)

Všimněte si, že jsme vrátili vlastnost exact do indexu .

Nyní uložte soubor a otestujte aplikaci přechodem z indexové stránky na stránku s informacemi a poté na neexistující stránku. Mělo by to fungovat, jak bylo zamýšleno.

Jakmile je mezi  prvky nalezena shoda ,  přestane hledat shody a vykreslí její prvek JSX. Jinak nevykreslí nic (tj. Null).

Nezapomeňte, že path="*" odpovídá každé instanci. Slouží jako záložní řešení, pokud žádná z předchozích tras nic nevykreslí.

Za tímto účelem s Switch deklarujete konkrétnější cestu před nejméně konkrétní.

Například pokud máte toto path="/about/:slug" a toto path="/about" v prvku s . Cesta s dřívější cestou by měla být v rámci přepínače na prvním místě.

Nedělejte si starosti s výše uvedeným :slug, k tomu se dostaneme, až začneme diskutovat o dynamickém směrování.

V tuto chvíli můžeme přejít na stránku /about nebo chybovou stránku pouze ručním zadáním adresy URL stránky do adresního řádku prohlížeče.

Pamatujte si, že z návrhu máme komponentu, Navbar která tyto odkazy zpracovává. Vytvořili jsme soubor Navbar.js ve složce /components.

Pokud ne, vytvořte jej. Pak přidejte jednoduchou funkční komponentu: 

import React from "react"

const Navbar = () => {
  return <div>Hello from Navbar</div>
}
export default Navbar

Uložte soubor a importujte jej do TodoContainer.js:

import Navbar from "./Navbar"

Poté vykreslete jeho instanci nad prvkem < Switch >:

return (
  <>
    <Navbar />
    <Switch>
      <Route exact path="/">
        ...
      </Route>
      <Route path="/about">
        <About />
      </Route>
      <Route path="*">
        <NotMatch />
      </Route>
    </Switch>
  </>
)

V kódu jsme znovu zavedli React fragment, který zabalí všechny prvky JSX. Uložte a zobrazte text Navbar v klientském rozhraní.

Dobrý. Přidejte navigační odkazy.

V komponentě Navbar začněte tím, že nad příkaz return přidáte pole objektů (obsahující všechny položky odkazů).

const links = [
  {
    id: 1,
    path: "/",
    text: "Home",
  },
  {
    id: 2,
    path: "/about",
    text: "About",
  },
]

To je docela snadné, protože tam můžete snadno přidat další odkazy, pokud chcete.

Dále aktualizujte return, abyste měli:

return (
  <nav className="navBar">
    <ul>
      {links.map(link => {
        return <li key={link.id}>{link.text}</li>
      })}
    </ul>
  </nav>
)

Jak vidíte, jednoduše procházíme pole links, abychom získali jednotlivé položky. Děláme to pomocí metody map. Nezapomeňte do položky zahrnout vlastnost key li.

Uložte soubor a uvidíte své položky zobrazené v rozhraní.

V tuto chvíli nejsou zobrazené položky propojeny s příslušnými stránkami. Uděláme to hned.

Obvykle pomocí < a href > často procházíme různé stránky webu. Ale to má za následek obnovení stránky. A v jednostránkové aplikaci to nechceme.

Směrovač React pro nás tedy poskytuje komponenty měniče cest, které můžeme použít k hladké navigaci. Komponenty < Link > < NavLink >.

I když můžeme použít kteroukoli z nich k navigaci po jiné trase, NavLink přidá style atributy k aktivním trasám. A můžeme to použít ke stylu trasy, aby uživatelé věděli, na jaké stránce se nacházejí.

Pojďme je použít. Začneme komponentou Link.

V komponentě Navbar importujte Link react-router-dom.

import { Link } from "react-router-dom"

Poté aktualizujte return, abyste měli:

return (
  <nav className="navBar">
    <ul>
      {links.map(link => {
        return (
          <li key={link.id}>
            <Link to={link.path}>{link.text}</Link>
          </li>
        )
      })}
    </ul>
  </nav>
)

Uložte soubor a otestujte svou aplikaci. Budete se moci pohybovat bez opětovného načtení stránky.

Složka Link bere vlastnosti to, kde jsme přiřadit název cesty. To odpovídá atributu href ve značce < a >.

Ale tady nejsme schopni zjistit, o jakou stránku se jedná, při pohledu na odkazy nebo při kontrole prvku v DevTools. Pojďme tedy nahradit < Link > < NavLink >. Váš kód by měl vypadat takto:

import React from 'react'

import { NavLink } from "react-router-dom"

const Navbar = () => {

  const links = [
    ...
  ]

  return (
    <nav className="navBar">
      <ul>
        ...
            <li key={link.id}>
              <NavLink to={link.path}>{link.text}</NavLink>
            </li>
        ...
      </ul>
    </nav>
  )
}
export default Navbar

Pokud soubor uložíte a podíváte se na frontend, v zobrazení prohlížeče neuvidíte žádné změny. Pokud ale zkontrolujete položky seznamu v konzole, uvidíte název třídy active aplikovaný na oba odkazy.

Abychom to napravili, uděláme to samé, co jsme dříve udělali pro < Route >. Přidáme vlastnost exact do NavLink. Můžete také pokračovat a použít výchozí název třídy a poté jej upravit. Ale ukážu vám, jak změnit název, pokud chcete. Jednoduše přidáte activeClassName do NavLink.

Aktualizujte jej, abyste měli:

return (
  <li key={link.id}>
    <NavLink to={link.path} activeClassName="active-link" exact>
      {link.text}
    </NavLink>
  </li>
)

Uložte soubor. Přejděte do souboru stylů (v našem případě App.css) a přidejte toto:

.active-link {
  color: orangered;
  text-decoration: underline;
}

Uložte soubor a otestujte svou práci. Mělo by to fungovat podle očekávání.

Vnořené a dynamické směrování

V tuto chvíli, pokud přejdete na stránku /about, se vykreslí komponenta About. Nyní řekněme, že chcete učinit dílčí cesty jako /about/about-app/about/about-author atd. Poté budete muset pochopit vnořené směrování.

V cestě je také relativní segment (například /about/relative-path) dynamický. Takže si to můžeme představovat takhle: /about/:slug. Kde :slug odpovídá relative-pathv URL. :slug (I když mohou být pojmenovány volně), se nazývá params. Použijeme to pro naše dynamické směrování.

Podívejme se na všechny tyto akce.

Na naší stránce s informacemi chceme zobrazit seznam dalších dvou stránek. Jeden pro autora a druhý o aplikaci.

To znamená, že k naší vnořené cestě dojde v komponentě About.

import React from 'react'

const About = (props) => {
  console.log(props)
  return (
    ...
  )
}
export default About

Uložte soubor. Při otevření konzoly /about přejděte do své aplikace a přejděte na stránku. Uvidíte, že props vrátí prázdný objekt.

Pojďme do souboru TodoContainer.js a dočasně z toho upravme prvek About Route:

<Route path="/about">
  <About />
</Route>

K tomuto:

<Route path="/about" component={About} />

Uložte soubor, znovu načtěte stránku /about a zkontrolujte konzolu.

nested_routing 

Tentokrát props vrací některé užitečné informace obsahující objekty historylocation match.

Zatím se zaměřuje na objekt match.

Zde máme přístup k urlpathparams atd.

K vytvoření vnořených odkazů budeme potřebovat adresu URLcesta pro vnořené cesty, zatímco params jsou potřebné pro dynamické trasy.

Proč je ale nedostáváme s dřívějším nastavením?

Před zavedením hoohks v routeru React je vlastnost component v prvku Route jednou z metod použitých k vykreslení komponent. Nyní je však vykreslíme jako podřízený prvek.

A prostřednictvím jednoho z háků můžeme mít přístup k objektu shody. Tento háček se nazývá useRouteMatch. Je také k dispozici v modulu react-router-dom.

Pojďme to použít.

Nejprve vraťte prvek Route v souboru TodoContainer.js, abyste měli:

<Route path="/about">
  <About />
</Route>

Uložte soubor.

Přejděte do souboru About.js a importujte hook takto:

import { useRouteMatch } from "react-router-dom"

Pokud tento hook zaznamenáte a zkontrolujete konzolu prohlížeče, měli byste mít přístup ke stejným vlastnostem, které jsme dříve viděli pro objekt match.

const About = () => {
  console.log(useRouteMatch())
  return (
    ...
  )
}
export default About

Nezapomeňte /about  zobrazit.

Nyní použijeme vrácená data k vytvoření vnořených odkazů a vnořených tras.

To je jednoduché.

Pamatujte si, že jsem se zmínil dříve, že url path se používají k vytvoření těchto vazeb.

Pojďme je tedy dostat z hooks (víme, že tam jsou, jak jsme viděli z posledního obrázku).

Přidejte toto nad return v komponentě About.

const { url, path } = useRouteMatch()
Then, update the return statement so you have:
return (
  <div>
    <ul>
      <li>
        <Link to={`${url}/about-app`}>About App</Link>
      </li>
      <li>
        <Link to={`${url}/about-author`}>About Author</Link>
      </li>
    </ul>
    <Route path={`${path}/:slug`}>
      <SinglePage />
    </Route>
  </div>
)

Všimněte si, že jsme představili několik věcí. Používáme komponentu < Links > < Route >. Aktualizujte tedy import, abyste měli:

import { Link, useRouteMatch, Route } from "react-router-dom"

Všimněte si také, že < SinglePage / > v prvku Route používáme komponentu.

Takže importujte takto:

import SinglePage from "./SinglePage"

Pak jej vytvořte ( SinglePage.js) uvnitř složky Pages. Můžete to zjednodušit přidáním této funkční komponenty.

import React from "react"

const SinglePage = () => {
  return <div>Hello from single page</div>
}
export default SinglePage

Uložte si soubory a procházejte různé stránky v aplikaci. Všimněte si, jak se adresa URL dynamicky mění na základě aktuálního zobrazení.

Co se děje?

Kód je až do tohoto bodu vysvětlující:

<Route path={`${path}/:slug`}>
  <SinglePage />
</Route>

path ${path} je /about. To jsme již viděli na posledním snímku obrazovky.

Ještě jedna věc, kterou je třeba poznamenat, je, že se :slug shoduje s čímkoli po /about/. To znamená, že :slug odpovídá about-app na /about/about-app stránku.

Budeme mít přístup k :slug od dítěte prvku SinglePage. Poté ji můžeme použít k dynamickému zobrazení správného obsahu na stránce.

Vezměte prosím na vědomí, že to nemusíte volat slug. Můžete jej pojmenovat, jak chcete.

Jakmile se cesta shoduje a podřízený prvek je vykreslen, můžeme použít hook s názvem, useParams abychom měli přístup k params aktuálnímu < Route >. V našem případě budeme mít přístup k vykreslené komponentě :slug.

V souboru SinglePage.js importujte useParams a přihlaste jej do konzoly.

import React from "react"
import { useParams } from "react-router-dom"

const SinglePage = () => {
  console.log(useParams())
  return <div>Hello from single page</div>
}
export default SinglePage

Uložte soubor. Při otevření konzoly přejděte na jednu stránku. Měli byste vidět stránku slug právě tam.

Nyní se podívejme, jak zobrazit dynamický obsah na základě cesty adresy URL stránky.

V souboru SinglePage.js přidejte tato data nad return:

const aboutData = [
  {
    slug: "about-app",
    title: "About the App",
    description:
      "In this app, you can add, delete, submit and edit items. To edit items, simply double click on it. Once you are done, press the enter key to resubmit. This app will persist your data in the browser local storage. So whether you reload, close your app or reopened it, you still have access to your to-dos items.",
  },
  {
    slug: "about-author",
    title: "About the Author",
    description:
      "This app was developed by Ibas Majid, a self-taught web developer and a technical writer. He is opened to freelance Gig. So go ahead and connect with ibas on Twitter @ibaslogic.",
  },
]

Potom přidejte následující pod data (ale nad return).

const { slug } = useParams()
const aboutContent = aboutData.find(item => item.slug === slug)
const { title, description } = aboutContent

Jak již bylo zmíněno dříve, aktuální slug stránky dostáváme prostřednictvím hooku useParams.

Potom pomocí metody find() vrátíme první objekt v poli, jehož slug odpovídá aktuálnímu slugu stránky. Vrácený objekt se poté uloží do proměnné aboutContent. Odtamtud ničíme title description.

Nyní můžete return aktualizovat, abyste měli:

return (
  <div>
    <h1>{title}</h1>
    <p>{description}</p>
  </div>
)

Uložte soubor a navštivte stránku About. Váš obsah by se měl na stránkách zobrazovat dynamicky.