Naučte se React praxí – React Router pro začátečníky

Představte si, že byste mohli změnit obsah webu nebo aplikace, aniž byste je museli znovu načítat. nemožné? Vůbec ne. Můžete to udělat pomocí něčeho, co se nazývá React Router. Jak? jsem rád, že se ptáš. Dnes vás provedu všemi kroky nezbytnými k uvedení React Router do provozu. Od této chvíle uvidíte opětovné načtení stránky jako historii. Jste připraveni prozkoumat, co je možné s React Routerem?

Živá ukázka na CodePen.

Instruktáž

Začněme tento tutoriál React Router rychlou instrukcí. Jsou dvě otázky, na které musíme odpovědět. Za prvé, co budeme stavět? Zadruhé, co budeme potřebovat k dokončení práce? Začněme první otázkou. Vytvoříme velmi jednoduchý web s více stránkami. A k propojení těchto stránek použijeme React Router. Jinými slovy, budete moci procházet web bez opětovného načítání stránky. Zní to skvěle?

Nyní odpovězme na druhou otázku. Budeme potřebovat řadu externích aktiv. Některé z těchto aktiv jsou nezbytné a některé jsou volitelné. Demo jsem postavil na Bootstrap 4 (alpha 6). To znamená, že jedním z volitelných prostředků je Bootstrap 4. A ano, budeme potřebovat jak CSS, tak JavaScript, protože budeme používat mobilní přepínatelnou navigaci Bootstrapu. Pokud to však nechcete používat, klidně to přeskočte. Dalším volitelným aktivem je jQuery.

Bootstrap vyžaduje ke spouštění skriptů knihovnu jQuery. Pokud tedy chceme používat mobilní navigaci nebo Bootstrap, můžete toto přeskočit. Použil jsem slim verzi jQuery. Jednalo se o volitelná aktiva. Nezbytné jsou React, ReactDOM a React Router. Kromě těchto aktiv jsem také použil překladač Babel. Babel nám umožňuje používat nejnovější syntaxi JavaScriptu, aniž bychom museli obětovat kompatibilitu prohlížeče.

Poslední věc, kterou bych měl zmínit, je verze každého aktiva. Už jsem zažil nějaké problémy s používáním různých verzí aktiv, zejména React Router. Budeme tedy používat React a ReactDOM verze 15.4.2. Verze React Router je 4.0.0-alpha.6. Verze Bootstrapu je také 4.0.0-alpha.6 (shoda okolností). Verze jQuery je 3.1.1 (Slim).

Poznámka:Používáme nejnovější verze všech aktiv (k tomuto datu – 16. ledna 2017).

HTML

Pokud jde o HTML, musíme udělat pouze jednu věc. Musíme vytvořit kontejner, kde později vykreslíme aplikaci React. Pojďme tedy vytvořit jeden div prvek s třídou „appRoot“. Díky tomu můžeme přejít na CSS (Sass).

HTML:

<div class="appRoot"></div>

CSS (Sass)

Jednou z výhod používání nějakého front-end frameworku, jako je Bootstrap, je to, že za nás dělá spoustu stylů. V důsledku toho budeme muset vytvořit menší množství vlastních stylů, aby byl tento tutoriál React Router zprovozněn a spuštěn. Nejprve změníme pozadí těla na obrázek. Protože je tento obrázek tmavý, budeme muset změnit barvu textu na bílou (#fff). Pro přidání kontrastu a zviditelnění textu použijeme : po pseudoprvek k vytvoření tmavého překrytí.

Dále použijeme sadu mediálních dotazů k použití různých velikostí obrázku na pozadí pro různá rozlišení, počínaje nejmenším. Jinými slovy, web navrhneme v souladu s mobilním přístupem. Musíme také zvýšit z-index kontejneru, který obsahuje text. V opačném případě by byla překryta.

Sass:

body {
 position: relative;
 color: #fff;
 background-image: url(https://source.unsplash.com/II2ulqB-118/480x320);
 background-repeat: no-repeat;
 background-position: top center;
 background-size: cover;
 
 // Creating dark overlay for background image
 &:after {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  content: "";
  width: 100%;
  height: 100vh;
  background: rgba(0,0,0,.5);
 }
}

@media screen and (min-width: 480px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/768x1080);
 }
}

@media screen and (min-width: 768px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/992x1080);
 }
}

@media screen and (min-width: 992px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/1400x1080);
 }
}

// Avoid covering the text by overlay
body .container {
 z-index: 3;
}

Ještě trochu leštění

Bude tam hodně místa. Obsah tedy můžeme vycentrovat vodorovně i svisle. Tedy kromě stránky galerie. To by mohlo způsobit nějaké problémy. Poté nastavíme výchozí styl pro h1 nadpis. Musíme také nastavit maximální šířku z img prvků na „100 %“. Jinak by mohly překrývat jeho kontejner a vytvořit nepořádek na stránce galerie. Poté změníme styl výchozí navigace Bootstrapu tak, aby odpovídala našemu tmavému designu. To zahrnuje přidání vlastních stylů pro navigaci odkazů.

Poslední věcí je přidat na stránku galerie nějaké další vlastní styly. Obrázky budou uvnitř mřížky 3×3 a mezi obrázky bychom měli přidat nějaké vertikální mezery. Bootstrap grid se postará o vodorovné rozestupy. Můžeme také přidat box-shadow přidat nějakou hloubku. Nakonec můžeme přidat nějaký styl pro hover stavu, jako je změna box-shadow .

Sass:

body:not(.page-gallery) .container {
 position: absolute;
 left: 0;
 top: 50%;
 right: 0;
 transform: translateY(-50%);
}

body:not(.page-gallery) .appRoot {
 position: relative;
 min-height: 320px;
 height: 100vh;
}

h1 {
 margin-top: 32px;
 margin-bottom: 32px;
 text-align: center;
 text-transform: uppercase;
}

img {
 max-width: 100%;
}

.nav {
 position: relative;
 z-index: 99;
}

.nav-link {
 font-weight: 700;
 color: #eee;
 transition: color .25s ease-out;
 
 &:focus,
 &:hover {
  color: #aaa;
 }
}

.nav-link-active,
.nav-link-active:focus {
 color: #fff;
 border-bottom: 2px solid;
}

// Add space above and below mobile nav
@media screen and (max-width: 768px) {
 .navbar-collapse {
  margin-top: 40px;
 }
 
 .navbar + div {
  margin-top: 40px;
 }
}

.page-gallery .col-4 {
 padding-top: 15px;
 padding-bottom: 15px;
}

.page-gallery img {
 box-shadow: 0 15px 35px rgba(50,50,93,.1),0 5px 15px rgba(0,0,0,.07);
 transition: box-shadow .25s ease-out;

 &:hover {
  box-shadow: 0 21px 35px rgba(50,50,93,.1),0 15px 15px rgba(0,0,0,.07);
 }
}

Vše v jednom kuse

Jako vždy dáme všechny kousky CSS (Sass) dohromady.

Sass:

body {
 position: relative;
 color: #fff;
 background-image: url(https://source.unsplash.com/II2ulqB-118/480x320);
 background-repeat: no-repeat;
 background-position: top center;
 background-size: cover;
 
 // Creating dark overlay for background image
 &:after {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  content: "";
  width: 100%;
  height: 100vh;
  background: rgba(0,0,0,.5);
 }
}

@media screen and (min-width: 480px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/768x1080);
 }
}

@media screen and (min-width: 768px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/992x1080);
 }
}

@media screen and (min-width: 992px) {
 body {
  background-image: url(https://source.unsplash.com/II2ulqB-118/1400x1080);
 }
}

// Avoid covering the text by overlay
body .container {
 z-index: 3;
}

body:not(.page-gallery) .container {
 position: absolute;
 left: 0;
 top: 50%;
 right: 0;
 transform: translateY(-50%);
}

body:not(.page-gallery) .appRoot {
 position: relative;
 min-height: 320px;
 height: 100vh;
}

h1 {
 margin-top: 32px;
 margin-bottom: 32px;
 text-align: center;
 text-transform: uppercase;
}

img {
 max-width: 100%;
}

.nav {
 position: relative;
 z-index: 99;
}

.nav-link {
 font-weight: 700;
 color: #eee;
 transition: color .25s ease-out;
 
 &:focus,
 &:hover {
  color: #aaa;
 }
}

.nav-link-active,
.nav-link-active:focus {
 color: #fff;
 border-bottom: 2px solid;
}

// Add space above and below mobile nav
@media screen and (max-width: 768px) {
 .navbar-collapse {
  margin-top: 40px;
 }
 
 .navbar + div {
  margin-top: 40px;
 }
}

.page-gallery .col-4 {
 padding-top: 15px;
 padding-bottom: 15px;
}

.page-gallery img {
 box-shadow: 0 15px 35px rgba(50,50,93,.1),0 5px 15px rgba(0,0,0,.07);
 transition: box-shadow .25s ease-out;

 &:hover {
  box-shadow: 0 21px 35px rgba(50,50,93,.1),0 15px 15px rgba(0,0,0,.07);
 }
}

JavaScript (Reagovat)

Dokončili jsme HTML a CSS (Sass). Nyní se musíme postarat o JavaScript. Toto je nejdůležitější část tohoto tutoriálu React Router. Do těch částí, které jsou složitější, jsem přidal komentáře přímo do kódu. Doufám, že vám to usnadní pochopení toho, jak React Route funguje a jak ji používat. Každopádně začněme. Naimportujeme potřebné díly z React Routeru a uložíme je do proměnné. Totéž můžeme udělat s HTML kontejnerem.

JavaScript (Reagovat):

// // Store all components of React Router inside variable
const {
 Route,
 Router,
 Link,
 hashHistory,
 IndexRoute,
 IndexLink
} = ReactRouter;

// Store the container for rendering our website
const appRoot = document.querySelector('.appRoot');

Hlavní součást

Dále vytvoříme naši první komponentu. To bude v podstatě naše výchozí nastavení. Tato komponenta bude obsahovat komponentu Navigace. Tuto komponentu vytvoříme později. Bude také obsahovat blok kódu, který nám umožní vykreslit aktuálně aktivní trasu. Nebo vykreslí stránku, kterou vybereme jako indexRoute. To se stane, když načteme stránku.

JavaScript (Reagovat):

// Component for main component
class App extends React.Component {
 render() {
  return (
   <div>
    <Navigation />

    {/* Render active Route or indexRoute */}
    {this.props.children}
   </div>
  );
 }
}

Komponenta domovské stránky

Druhá komponenta, kterou vytvoříme v tomto tutoriálu React Router, bude komponenta pro naši domovskou stránku. Rozhodl jsem se udělat tento tutoriál jednoduchý. V důsledku toho bude kód pro všechny komponenty používat převážně základní HTML kód. A většina tříd bude z Bootstrapu. Jednou výjimkou budou komponenty React Router a dvě React metody. Tyto metody jsou componentWillMount() a componentWillUnmount() .

První metoda, componentWillMount () bude vyvolána těsně před vykreslením samotné komponenty. Druhý, componentWillUnmount() těsně před zničením součásti. Tyto metody použijeme v každé komponentě stránky k přidání/odebrání konkrétních tříd CSS do těla prvek.

JavaScript (Reagovat):

// Component for Homepage
class Home extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-home');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-home');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2 text-center'>
      <h1>Anthony Sabia</h1>
 
      <p>A web designer &amp; developer from New York, USA, who focuses on building interactive experiences &amp; mobile apps, currently leading a design team at Spotify.</p>
     </div>
    </div>
   </div>
  );
 }
}

O komponentě stránky

Třetí komponentou, kterou vytvoříme, je komponenta pro stránku about. Tato komponenta bude velmi podobná domovské stránce. Jen obsah HTML bude jiný.

JavaScript (Reagovat):

// Component for About page
class About extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-about');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-about');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2'>
      <h1>About Me</h1>

      <p>I like to focus on creating unique and clean design concepts, prototypes and interactive experiences. My expertise and skills cover the whole design process, from research and to visual design and execution.</p>

      <p>I work with a wide range of clients, from startups to well-established companies. My clients are usually looking for user-centered design and product design visions to help them improve their product and grow their brand.</p>
     </div>
    </div>
   </div>
  );
 }
}

Kontaktujte součást stránky

Další komponentou, kterou vytvoříme pro tento tutoriál React Router, bude komponenta pro kontaktní stránku. Tato komponenta bude trochu jiná. Přidáme krátký kontaktní formulář.

JavaScript (Reagovat):

// Component for Contact page
class Contact extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-contact');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-contact');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-8 push-md-2 col-lg-6 push-lg-3'>
      <h1>Let's get in touch!</h1>

      <form formAction='' className='card-form'>
       <div className='row form-group'>
        <div className='col-6'>
         <input className='form-control' name='formName' id='formName' type='text' placeholder='Your name' />
        </div>

        <div className='col-6'>
         <input className='form-control' name='formEmail' id='formEmail' type='email' placeholder='Your email address' />
        </div>
       </div>

       <fieldset className='form-group'>
        <textarea className='form-control' name='formMessage' id='formMessage' placeholder='Your message' required ></textarea>
       </fieldset>

       <fieldset className='form-group text-center'>
        <button className='btn btn-primary' type='submit'>Send message</button>
       </fieldset>
      </form>
     </div>
    </div>
   </div>
  );
 }
}

Komponenta stránky galerie

Další je komponenta pro stránku galerie. Jak jsem již zmínil v části o CSS, tato stránka bude obsahovat devět příkladů práce (nebo záběrů). Tyto záběry uspořádáme do sítě tří řad, z nichž každá obsahuje tři sloupce. Každý sloupec bude obsahovat jeden výstřel.

JavaScript (Reagovat):

// Component for Gallery page
class Gallery extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-gallery');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-gallery');
 }

 render() {
  return (
   <div className='container'>
    <h1>Featured Projects</h1>

    <p className='mb-4 text-center'>Selection of projects finished between years 2014 — 2016.</p>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/40433/screenshots/3205585/dri.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/40433/screenshots/3213974/untitled-1.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/182336/screenshots/3219163/dribbble_shot.png' alt='' />
     </div>
    </div>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/692322/screenshots/3217252/profile.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/13307/screenshots/3208495/web_site_tea.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/784847/screenshots/3218599/roposo.com_website_exploration.png' alt='' />
     </div>
    </div>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/66340/screenshots/3206003/home.jpg' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/273461/screenshots/3218915/chewy.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/274994/screenshots/3218870/dashboard.png' alt='' />
     </div>
    </div>
   </div>
  );
 }
}

Komponenta stránky 404

Poslední komponenta stránky, kterou dnes vytvoříme, bude pro stránku 404.

JavaScript (Reagovat):

// Component for NotFound - 404 - page
class NotFound extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-not-found');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-not-found');
 }
 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2 text-center'>
      <h1 className='mt-4 mb-4'>404!</h1>

      <h2>The page you are looking for doesn't exist.</h2>
     </div>
    </div>
   </div>
  );
 }
}

Navigační komponenta

Máme komponenty pro všechny stránky. Stále však zbývá jeden komponent, který musíme vytvořit. Tato komponenta je určena pro hlavní navigaci. Bez toho by byl tento tutoriál React Router docela k ničemu. No, mohli bychom použít tlačítka. Myslím si však, že lidé jsou zvyklí spíše na klasickou navigaci. Kód pro tuto komponentu se bude lišit od kódu, který jsme napsali výše. Velká část, jako je třída , nav , li a tlačítko elementy je výchozí strukturou bootstrapu.

Navíc použijeme dvě komponenty, od React Router. Tyto komponenty jsou Odkaz a IndexLink . Částečně díky těmto komponentám můžeme propojit konkrétní odkaz s konkrétní stránkou. Jak jsem zmínil, přidal jsem komentáře, abych vysvětlil, jak tyto dvě komponenty fungují přímo v kódu ({/* … */} ). Stručně řečeno, Odkaz komponenta funguje jako > tag. S React Routerem jej můžeme použít k vykreslení konkrétní stránky (komponenty).

IndexLink je téměř stejný jako Odkaz . Rozdíl je v tom, že tento odkaz je aktivní pouze tehdy, když je aktivní trasa indexu (URL odpovídá „/“). Jinak by byl tento odkaz aktivní na každé stránce, protože URL vždy obsahuje „/“. Poslední věc je, že používáme activeClassName k dynamickému připojení třídy k odkazu, když je aktivní – související stránka se vykreslí.

JavaScript (Reagovat):

// Component for Navigation
class Navigation extends React.Component {
 render() {
  return (
   <nav className='navbar navbar-toggleable-sm'>
    <button className='navbar-toggler navbar-toggler-right' type='button' data-toggle='collapse' data-target='#navbarNav' aria-controls='navbarNav' aria-expanded='false' aria-label='Toggle navigation'>
     <span className='navbar-toggler-icon'></span>
    </button>

    <div className='collapse navbar-collapse justify-content-center' id='navbarNav'>
     <ul className='nav flex-column flex-md-row' role='nav'>
      <li className='nav-item'>
       {/* Note about Links: parent route is active when any child route is active (it has always class ¨'nav-link-active'). We want the link to '/' be active only when the index route is active. For this reason, we will use 'IndexLink' */}
       <IndexLink to='/' className='nav-link' activeClassName='nav-link-active'>Home</IndexLink>
       {/* 'activeClassName' allow us to add class when the link is active (current Route). Another option is using 'activeStyle' and CSS styles. */}
      </li>

      <li className='nav-item'>
       {/* Link is similar to <a/> tag. The difference is that Link is aware of the Router (screen) it is rendered in. It allows you to wire together links with Routes (via 'to' attribute). */}
       <Link className='nav-link' activeClassName='nav-link-active' to='/about'>About</Link>
      </li>

      <li className='nav-item'>
       <Link className='nav-link' activeClassName='nav-link-active' to='/gallery'>Gallery</Link>
      </li>

      <li className='nav-item'>
       <Link className='nav-link' activeClassName='nav-link-active' to='/contact'>Contact</Link>
      </li>
     </ul>
    </div>
   </nav>
  );
 }
}

Připravit, nastavit, vykreslit!

Posledním krokem ke spuštění tohoto tutoriálu React Router je vytváření tras a jejich zobrazování. K tomu použijeme Router , Trasa a IndexRoute komponenty z React Router. Zabalíme všechny Trasy a jeden IndexRoute uvnitř Směrovače . Router bude mít jeden atribut – historii . To nám pomůže spravovat historii směrování pomocí hash části adresy URL. Nyní můžete přejít na Trasy .

Rozdíl mezi Trasou a IndexRoute je, že nám IndexRoute umožní vykreslit komponentu, když navštívíme „/“ nebo „domovskou“ stránku. Každá Trasa bude mít dva atributy, cesta a komponenta . Cesta určí, jak bude URL vypadat. Komponenta určí, která komponenta se má na této adrese URL vykreslit. IndexRoute bude mít pouze jeden atribut – komponenta . Nakonec musíme říci, kde chceme web vykreslit. Použijme appRoot proměnná od začátku.

JavaScript (Reagovat):

ReactDOM.render((
 <Router history={hashHistory}>
  {/* 'hashHistory' manages the routing history with the hash portion of the URL. */}
  <Route path='/' component={App}>
   {/* IndexRoute allows us to render a component when we visit '/'.
   Note: IndexRoute has no path - it becomes this.props.children of the parent when no other child of the parent matches. */}
   <IndexRoute component={Home} />
   {/* Each Route is child of 'App'. This allows the components inside of App share the navigation. Otherwise, we would need to add Navigation compoonent into every page (component) */}
   <Route path='/about' component={About} />
   <Route path='/gallery' component={Gallery} />
   <Route path='/contact' component={Contact} />
   <Route path='*' component={NotFound} />
  </Route>
 </Router>
), appRoot);

Vše v jednom kuse

Opět dáme vše dohromady.

JavaScript (Reagovat):

// // Store all components of React Router inside variable
const {
 Route,
 Router,
 Link,
 hashHistory,
 IndexRoute,
 IndexLink
} = ReactRouter;

// Store the container for rendering our website
const appRoot = document.querySelector('.appRoot');

// Component for main component
class App extends React.Component {
 render() {
  return (
   <div>
    <Navigation />

    {/* Render active Route or indexRoute */}
    {this.props.children}
   </div>
  );
 }
}

// Component for Homepage
class Home extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-home');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-home');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2 text-center'>
      <h1>Anthony Sabia</h1>
 
      <p>A web designer &amp; developer from New York, USA, who focuses on building interactive experiences &amp; mobile apps, currently leading a design team at Spotify.</p>
     </div>
    </div>
   </div>
  );
 }
}

// Component for About page
class About extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-about');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-about');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2'>
      <h1>About Me</h1>

      <p>I like to focus on creating unique and clean design concepts, prototypes and interactive experiences. My expertise and skills cover the whole design process, from research and to visual design and execution.</p>

      <p>I work with a wide range of clients, from startups to well-established companies. My clients are usually looking for user-centered design and product design visions to help them improve their product and grow their brand.</p>
     </div>
    </div>
   </div>
  );
 }
}

// Component for Contact page
class Contact extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-contact');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-contact');
 }

 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-8 push-md-2 col-lg-6 push-lg-3'>
      <h1>Let's get in touch!</h1>

      <form formAction='' className='card-form'>
       <div className='row form-group'>
        <div className='col-6'>
         <input className='form-control' name='formName' id='formName' type='text' placeholder='Your name' />
        </div>

        <div className='col-6'>
         <input className='form-control' name='formEmail' id='formEmail' type='email' placeholder='Your email address' />
        </div>
       </div>

       <fieldset className='form-group'>
        <textarea className='form-control' name='formMessage' id='formMessage' placeholder='Your message' required ></textarea>
       </fieldset>

       <fieldset className='form-group text-center'>
        <button className='btn btn-primary' type='submit'>Send message</button>
       </fieldset>
      </form>
     </div>
    </div>
   </div>
  );
 }
}

// Component for Gallery page
class Gallery extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-gallery');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-gallery');
 }

 render() {
  return (
   <div className='container'>
    <h1>Featured Projects</h1>

    <p className='mb-4 text-center'>Selection of projects finished between years 2014 — 2016.</p>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/40433/screenshots/3205585/dri.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/40433/screenshots/3213974/untitled-1.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/182336/screenshots/3219163/dribbble_shot.png' alt='' />
     </div>
    </div>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/692322/screenshots/3217252/profile.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/13307/screenshots/3208495/web_site_tea.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/784847/screenshots/3218599/roposo.com_website_exploration.png' alt='' />
     </div>
    </div>

    <div className='row'>
     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/66340/screenshots/3206003/home.jpg' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/273461/screenshots/3218915/chewy.png' alt='' />
     </div>

     <div className='col-4'>
      <img src='https://d13yacurqjgara.cloudfront.net/users/274994/screenshots/3218870/dashboard.png' alt='' />
     </div>
    </div>
   </div>
  );
 }
}

// Component for NotFound - 404 - page
class NotFound extends React.Component {
 componentWillMount() {
  document.body.classList.add('page-not-found');
 }

 componentWillUnmount() {
  document.body.classList.remove('page-not-found');
 }
 render() {
  return (
   <div className='container'>
    <div className='row'>
     <div className='col-md-10 push-md-1 col-lg-8 push-lg-2 text-center'>
      <h1 className='mt-4 mb-4'>404!</h1>

      <h2>The page you are looking for doesn't exist.</h2>
     </div>
    </div>
   </div>
  );
 }
}

// Component for Navigation
class Navigation extends React.Component {
 render() {
  return (
   <nav className='navbar navbar-toggleable-sm'>
    <button className='navbar-toggler navbar-toggler-right' type='button' data-toggle='collapse' data-target='#navbarNav' aria-controls='navbarNav' aria-expanded='false' aria-label='Toggle navigation'>
     <span className='navbar-toggler-icon'></span>
    </button>

    <div className='collapse navbar-collapse justify-content-center' id='navbarNav'>
     <ul className='nav flex-column flex-md-row' role='nav'>
      <li className='nav-item'>
       {/* Note about Links: parent route is active when any child route is active (it has always class ¨'nav-link-active'). We want the link to '/' be active only when the index route is active. For this reason, we will use 'IndexLink' */}
       <IndexLink to='/' className='nav-link' activeClassName='nav-link-active'>Home</IndexLink>
       {/* 'activeClassName' allow us to add class when the link is active (current Route). Another option is using 'activeStyle' and CSS styles. */}
      </li>

      <li className='nav-item'>
       {/* Link is similar to <a/> tag. The difference is that Link is aware of the Router (screen) it is rendered in. It allows you to wire together links with Routes (via 'to' attribute). */}
       <Link className='nav-link' activeClassName='nav-link-active' to='/about'>About</Link>
      </li>

      <li className='nav-item'>
       <Link className='nav-link' activeClassName='nav-link-active' to='/gallery'>Gallery</Link>
      </li>

      <li className='nav-item'>
       <Link className='nav-link' activeClassName='nav-link-active' to='/contact'>Contact</Link>
      </li>
     </ul>
    </div>
   </nav>
  );
 }
}

ReactDOM.render((
 <Router history={hashHistory}>
  {/* 'hashHistory' manages the routing history with the hash portion of the URL. */}
  <Route path='/' component={App}>
   {/* IndexRoute allows us to render a component when we visit '/'.
   Note: IndexRoute has no path - it becomes this.props.children of the parent when no other child of the parent matches. */}
   <IndexRoute component={Home} />
   {/* Each Route is child of 'App'. This allows the components inside of App share the navigation. Otherwise, we would need to add Navigation compoonent into every page (component) */}
   <Route path='/about' component={About} />
   <Route path='/gallery' component={Gallery} />
   <Route path='/contact' component={Contact} />
   <Route path='*' component={NotFound} />
  </Route>
 </Router>
), appRoot);

Závěrečné úvahy o React Router

To je ono! Právě jste vytvořili svůj vlastní web pomocí React Route! Od této chvíle můžete vytvářet weby a aplikace, které nevyžadují opětovné načítání stránky. Nakonec to nebylo tak těžké. Nebo ano? Doufám, že jste se při práci na tomto tutoriálu bavili. Také doufám, že jste se naučili něco nového, něco, co můžete vědět, že můžete použít jinde. To je pro dnešek vše. Uvidíme se zde znovu v pátek!