React.js. Начало работы. Часть 11 из 12

30.10.2019

Теги: JavaScriptReact.jsWeb-разработкаКомпонентМенюНавигацияФреймворк

Главное отличие одностраничных приложений от традиционных многостраничных заключается в том, что навигация по одностраничному приложению не предполагает перехода на совершенно новую страницу. Вместо этого все страницы (называемые представлениями) обычно загружаются внутри одной и той же начальной страницы. Главная сложность в разработке SPA — сделать так, чтобы одностраничное приложение вело себя таким образом, как привыкли пользователи:

  1. URL-адрес, отображаемый в адресной строке, должен всегда отображать то, что пользователь просматривает.
  2. Пользователь ожидает, что сможет использовать кнопки истории браузера «Назад» и «Вперед».
  3. Пользователь должен иметь возможность перейти к определенному представлению напрямую, по URL-адресу.

Чтобы решить все эти проблемы, существует множество библиотек JavaScript, самая главная из которых — React Router.

Создание SPA с использованием React Router

Итак, создаем новое приложение:

> create-react-app reactspa

Переходим в директорию reactspa и устанавливаем React Router:

> cd reactspa
> npm install --save react-router-dom

Эта команда скопирует необъодимые файлы React Router и зарегистрирует их в файле package.json, чтобы наше приложение было в курсе существования библиотеки.

Чтобы начать разработку приложения с нуля, удаляем все файлы из директорий src и public. И создаем файл index.html в директории public:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
    <title>React Router Example</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

В директории src создаем файл index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import Main from './Main';

ReactDOM.render(
    <Main/>,
    document.getElementById('root')
);
Способ создания одностраничного приложения ничем не отличается от того, как мы создавали все предыдущие приложения. У нас есть основной родительский компонент. Каждая отдельная «страница» приложения будет отдельным компонентом. Библиотека React Router привносит в основном возможность выбора компонентов, которые нужно показать или скрыть. Вся навигация связана с адресной строкой браузера и кнопками «Назад» и «Вперед».

Отображение начального фрейма

При создании SPA часть его страницы всегда остается статической. Эта статическая часть, также называемая фреймом приложения, может быть одним невидимым элементом HTML, который действует как контейнер для всего контента. Или, может включать в себя некоторые дополнительные видимые объекты, такие как шапка, подвал или навигация.

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

В директории src создаем файл Main.js:

import React, {Component} from 'react';

class Main extends Component {
    render() {
        return (
            <div>
                <h1>Простое SPA-приложение</h1>
                <ul className="header">
                    <li><a href="/">Главная</a></li>
                    <li><a href="/catalog">Каталог</a></li>
                    <li><a href="/contact">Контакты</a></li>
                </ul>
                <div className="content"></div>
            </div>
        );
    }
}

export default Main;

Проверим работу приложения:

> npm start

Создание страниц с контентом

У нашего приложения три страницы с контентом. Этот контент будет простым компонентом, который выводит простой JSX-код. Так что создаем три файла: Home.js, Catalog.js и Contact.js:

import React, {Component} from 'react';

class Home extends Component {
    render() {
        return (
            <div>
                <h2>Главная</h2>
                <p>
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
                    labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
                    laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
                    voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
                    non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
                </p>
            </div>
        );
    }
}

export default Home;
import React, {Component} from 'react';

class Catalog extends Component {
    render() {
        return (
            <div>
                <h2>Каталог</h2>
                <ul>
                    <li>Lorem ipsum dolor sit amet</li>
                    <li>Сonsectetur adipiscing elit</li>
                    <li>Sed do eiusmod tempor incididunt ut</li>
                    <li>Labore et dolore magna aliqua</li>
                </ul>
                <p>
                    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
                    commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
                    dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
                    culpa qui officia deserunt mollit anim id est laborum.
                </p>
            </div>
        );
    }
}

export default Catalog;
import React, {Component} from 'react';

class Contact extends Component {
    render() {
        return (
            <div>
                <h2>Главная</h2>
                <p>
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
                    labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
                    laboris nisi ut aliquip ex ea commodo consequat.
                </p>
                <ul>
                    <li>Duis aute irure dolor in reprehenderit in voluptate</li>
                    <li>Velit esse cillum dolore eu fugiat nulla pariatur</li>
                    <li>Excepteur sint occaecat cupidatat non proident sunt in</li>
                    <li>Culpa qui officia deserunt mollit anim id est laborum</li>
                </ul>
            </div>
        );
    }
}

export default Contact;

Использование библиотеки React Router

У нас теперь есть фрейм приложения в виде компонента Main. И есть страницы с контеном, представленные компонентами Home, Catalog и Contact. Чтобы начать использовать React Router, добавим инструкции import в компонент Main:

import React, {Component} from 'react';
import {Route, NavLink, HashRouter} from 'react-router-dom'
import Home from './Home';
import Catalog from './Catalog';
import Contact from './Contact';

class Main extends Component {
    /* ..... */
}

export default Main;

Библиотека React Router в процессе работы определяет так называемую область маршрутизации. В этой области находится следующее:

  1. Ссылки для навигации
  2. Контейнер для загрузки контента

Компонент HashRouter создает основу для навигации и обработки истории боаузера. И нам потребуется специализированный компонент NavLink, чтобы заменить ссылки. А компонент Route позволяет сопоставить контент с URL-адресом страницы:

import React, {Component} from 'react';
import {Route, NavLink, HashRouter} from 'react-router-dom'
import Home from './Home';
import Catalog from './Catalog';
import Contact from './Contact';

class Main extends Component {
    render() {
        return (
            <HashRouter>
                <div>
                    <h1>Простое SPA-приложение</h1>
                    <ul className="header">
                        <li><NavLink to="/">Главная</NavLink></li>
                        <li><NavLink to="/catalog">Каталог</NavLink></li>
                        <li><NavLink to="/contact">Контакты</NavLink></li>
                    </ul>
                    <div className="content">
                        <Route path="/" component={Home} />
                        <Route path="/catalog" component={Catalog} />
                        <Route path="/contact" component={Contact} />
                    </div>
                </div>
            </HashRouter>
        );
    }
}

export default Main;

Компонент Route содержит свойство path. Значение, присвоенное этому свойству, определяет активность пути. Когда путь активен, соответствующий компонент визуализируется.

Запустим приложение и посмотрим, что получилось. При переходе по ссылкам, соответствующий ссылке компонент визуализируется. Но содержимое главной страницы показывается всегда, даже при переходе по ссылкам «Каталог» или «Контакты»:

Исправление путей маршрутизации

Контент компонента Home отображается всегда, поскольку путь до него равен «/». Компоненты Catalog и Contact тоже содержат сомвол «/» в имени пути. Это означает, что компонент Home соответствует любому пути, по которому мы переходим. Нам нужно строгое соответствие:

<div className="content">
    <Route exact path="/" component={Home} />
    <Route path="/catalog" component={Catalog} />
    <Route path="/contact" component={Contact} />
</div>

Добавление стилевого оформления

Создаем файл index.css в директории src:

body {
    background-color: #fc0;
    padding: 20px;
    margin: 0;
}
h1, h2, li, p, ul {
    font-family: Helvetica,Arial,sans-serif;
}
ul.header {
    background-color:#111;
    padding: 0;
}
    ul.header li {
        display: inline;
        list-style-type: none;
        margin: 0;
    }
        ul.header li a {
            color: #fff;
            font-weight: 700;
            text-decoration: none;
            padding: 20px;
            display: inline-block;
            }
.content {
    background-color: #fff;
    padding:20px;
}
    .content h2 {
        padding: 0;
        margin: 0;
}
    .content li {
        margin-bottom: 10px;
    }

И добавим импорт этой таблицы стилей в компонент Main::

import React, {Component} from 'react';
import {Route, NavLink, HashRouter} from 'react-router-dom'
import Home from './Home';
import Catalog from './Catalog';
import Contact from './Contact';
import './index.css';

class Main extends Component {
    /* ..... */
}

export default Main;

Выделение активной ссылки

Когда мы кликаем по ссылке, ей автоматически присваивается css-класс active. Добавим стилевое оформление для активной ссылки:

.active {
    background-color: #09f;
}

Выглядит красиво, но ссылка «Главная» подсвечена всегда. Исправить это просто:

<ul className="header">
    <li><NavLink exact to="/">Главная</NavLink></li>
    <li><NavLink to="/catalog">Каталог</NavLink></li>
    <li><NavLink to="/contact">Контакты</NavLink></li>
</ul>

Поиск: JavaScript • React.js • Web-разработка • Меню • Навигация • Фреймворк • Компонент • SPA • Router

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.