React - это библиотека JavaScript для создания пользовательских интерфейсов. В парадигме React каждая часть пользовательского интерфейса является компонентом, который управляет своим собственным автономным состоянием (данными) и функциями.
React, как и другие интерфейсные JavaScript-фреймворки, полезен для создания одностраничных приложений (SPA). Это веб-приложения, которым не требуется перезагрузка полной страницы при изменении представления. Вместо этого они меняют представления в или из раздела страницы, когда пользователь перемещается по приложению.
Хотя SPA обеспечивают пользователям удобную навигацию, ожидаются функции маршрутизации традиционных веб-сайтов.
Например:
- у каждого представления на экране должен быть свой собственный URL-адрес, чтобы я мог добавить страницу в закладки.
- Кнопки вперед и назад должны перемещать меня вперед или назад в моей истории просмотров.
- Вложенные представления и представления с параметрами должны поддерживаться, например
example.com/products/shoes/101
.
В сообществе React React Router - любимая библиотека для обработки маршрутизации. Самым привлекательным аспектом этой версии библиотеки является то, что она «просто React». Маршруты - это просто компоненты, которые отображаются на экране при запуске приложения. Они не определены во внешних файлах, как в других фреймворках.
Предпосылки
Вам потребуется следующее: Базовые знания React, Git установлен на вашем компьютере и NPM установлен. на вашем компьютере r.
Настройка
Если у вас установлен Git, найдите пустые исходные файлы (в ветке master) и клонируйте их на свой компьютер, используя:
git clone https://github.com/emmyyusufu/react-router-demos.git
Откройте папку в текстовом редакторе и найдите вложенные папки внутри:
Это сообщение разделено на четыре подраздела в соответствии с папками: Basic routing
, Nested routing
, Nested routing with path parameters
и Authenticated routing
.
Чтобы запустить демонстрационные версии, откройте заданную папку в вашем терминале, затем запустите npm install
, а затем npm start
.
# 1 Базовая маршрутизация
Начнем с нуля. Обратите внимание на структуру папок основной папки маршрутизации.
Все демонстрации в этом посте изначально были созданы с использованием create-react-app. Это дает некоторые преимущества, такие как уже настроенный сервер Webpack, который объединит весь файл JavaScript в нашем приложении в файл bundle.js
, который будет прикреплен к index.html
file во время выполнения. Во время выполнения сервер разработки Webpack будет отслеживать любые изменения в нашем файле и обновлять его по мере выполнения приложения во время разработки.
Я создал components/
папку, в которой хранятся все наши компоненты. Обратите внимание, что:
index.js
это входной файл для всех.js
файлов в нашем приложении. Здесь будет выполняться объединение Webpack, поэтому все.js
файлы должны быть импортированы в него.App.js
будет содержать все, что касается нашего приложения React.
По умолчанию приложение create-response-app не помещает App.js
в эту папку. Но поскольку я изменил структуру папок, я внес соответствующие изменения в URL-адрес пути и импортировал его в index.js
. Чтобы узнать больше о приложении create-react-app, эта справка будет полезна.
Перейдите в первую папку 01-basic-routing
и запустите npm install
.
Откройте файл App.js
, и вы должны увидеть следующее:
import React, { Component } from 'react'; import '../styles/App.css'; // import route Components here class App extends Component { render() { return ( <div className="App"> <div className="container"> <ul> <li><a href="">Hello</a></li> <li><a href="">About</a></li> <li><a href="">Books</a></li> </ul> <hr/> {/* Routes will go here */} </div> </div> ); } } export default App;
Запустите npm start и просмотрите приложение. Изменений пока нет.
Давайте установим React Router через NPM. Открыв папку в вашем терминале, запустите:
npm install react-router-dom
Почему react-router-dom
? Это связано с тем, что библиотека маршрутизатора React состоит из трех пакетов: react-router
, react-router-dom
и react-router-native
.
react-router
- это основной пакет для маршрутизатора, тогда как два других зависят от среды. Вам следует использовать react-router-dom
, если вы создаете для Интернета, и react-router-native
, если вы работаете в среде разработки мобильных приложений с помощью React Native.
Импортируйте следующее в App.js
// import route Components here import { BrowserRouter as Router, Route, Link, Switch, Redirect } from 'react-router-dom'
Позже мы поймем, что делают эти компоненты. Все компоненты маршрутизации зависят от BrowserRouter
предоставления им API истории браузера HTML5.
Обратите внимание, что в компонентах React первая буква написана с заглавной буквы, чтобы их можно было идентифицировать иначе, чем теги HTML по умолчанию.
History API - это объект, который позволяет нам управлять текущим местоположением через history.location
, а также предыдущими местоположениями. Думайте о свойстве location
объекта как о массиве. Текущее местоположение - это последний элемент в массиве, и мы манипулируем массивом с помощью таких методов, как history.push()
илиhistory.replace
. Какие бы манипуляции с массивом ни производились, это вызовет переход страницы в текущее местоположение. Вот что происходит за кулисами при использовании компонентов Link
и Redirect
, как мы скоро увидим.
Мы импортировали содержимое BrowserRouter
в переменную Router
. Нам нужно обернуть им все наше приложение, чтобы оно предоставляло необходимые API по всему приложению. В App.js
добавить:
import React, { Component } from 'react'; import '../styles/App.css'; // import route Components here import { BrowserRouter as Router, Route, Link, Switch, Redirect } from 'react-router-dom' class App extends Component { render() { return ( <Router> <div className="App"> <div className="container"> <ul> <li><a href="">Hello</a></li> <li><a href="">About</a></li> <li><a href="">Books</a></li> </ul> <hr/> {/* Routes will go here */} </div> </div> </Router> ); } } export default App;
Компонент ‹Маршрут /›
Приступим к изучению компонента Route
. Этот компонент отображает страницу, если текущее расположение URL совпадает с указанным в нем параметром path
. Он также принимает реквизиты component
, render
и children
.
Давайте создадим наш, где его написанные {/ * Routes будут идти сюда * /}:
<Route path="/hello" component={Hello} /> <Route path="/about" component={About} /> <Route path="/books" component={Books} />
Но этих компонентов не существует! Да ты прав.
Опять же, прежде чем мы их создадим, давайте добавим еще импорт в App.js
. Импорт из HelloComponent.js
, AboutComponent.js
и BooksComponent.js
с использованием Hello
, About
и Books
в качестве переменных. В опоре component={}
фигурные скобки используются для обозначения переменных, а не строк.
import React, { Component } from 'react'; import '../styles/App.css'; import Hello from './HelloComponent'; import About from './AboutComponent'; import Books from './BooksComponent'; // import route Components here import { BrowserRouter as Router, Route, Link, Switch, Redirect } from 'react-router-dom'
Обратите внимание, что render
похож на component={}
, но позволяет нам определять компонент прямо здесь:
<Route path="/hello" render={() => { return ( <div className="jumbotron"> <h1 className="display-3">Hello, world!</h1> </div> ); }}/>
Перейдите к пустому файлу HelloComponent.js
и вставьте:
import React from 'react'; const Hello = () => { return ( <div className="jumbotron"> <h1 className="display-3">Hello, world!</h1> </div> ); } export default Hello;
Выше мы использовали функциональный компонент без сохранения состояния (отсюда и стрелочную функцию). Мы используем их для компонентов, которые отображают на веб-страницу только статический контент, в отличие от компонентов, которые отображают / изменяют контент с сохранением состояния.
Если вы не заметили, мы используем стили Bootstrap 4 в нашем App.css
файле, отсюда класс jumbotron
в div
.
// inside App.css. You'll need internet connection to load the Bootstrap 4 styles. .App { padding-top: 50px; } @import url('https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css');
Перейдите к пустому файлу AboutComponent.js
и вставьте:
import React from 'react'; const About = () => { return ( <div className="jumbotron"> <h1 className="display-3">About Me</h1> </div> ); } export default About;
Наконец, перейдите к пустому файлу BooksComponent.js
и вставьте:
import React from 'react'; const Books = () => { return ( <div className="jumbotron"> <h1 className="display-3">My Books</h1> </div> ); } export default Books;
Еще одна вещь, которую нам нужно завершить в этом разделе, - это компонент Link
.
Компонент ‹Link› ‹/Link›
Он заменяет HTML-тег <a href=""></a>
по умолчанию. Он принимает опору to=""
, которая указывает на адрес URL, по которому мы хотим перейти.
Внутри App.js
замените теги привязки по умолчанию на Link
:
<ul> <li><Link to="/hello">Hello</Link></li> <li><Link to="/about">About</Link></li> <li><Link to="/books">Books</Link></li> </ul>
Запустите npm start
со своего терминала и посмотрите полное приложение:
Как вы визуализируете компонент, если посещается /
URL, например, целевая или домашняя страница. Возможно, вы захотите создать для него маршрут:
<Route path="/" component={Home} />
Это нормально, но помните, что в других путях есть /
. Поэтому, если мы посетили другие URL-адреса, такие как /hello
, /about
и /books
, компонентHome
будет продолжать отображаться по умолчанию. Чтобы исправить это, напишите другую опору exact
, установив для нее значение true
, или просто напишите exact
.
<Route path="/" exact={true} component={Home} />
Это гарантирует, что компонент Home
будет отображаться только в тех случаях, когда URL-адрес в точности совпадает с этим: /
.
Создайте новый HomeComponent.js
файл в папке components/
. Вставьте это в:
import React from 'react'; const Home = () => { return ( <div className="jumbotron"> <h1 className="display-3">Landing page</h1> </div> ); } export default Home;
Импортировать в App.js
import Home from './HomeComponent';
Добавить в список маршрутов
<Route exact={true} path="/" component={Home} /> <Route path="/hello" component={Hello} /> <Route path="/about" component={About} /> <Route path="/books" component={Books} />
Посетите http://localhost:3000
и просмотрите:
Проведите несколько экспериментов. Удалите exact={true}
из домашнего маршрута и посмотрите, что произойдет. Вы поймете, почему это важно.
Компонент ‹Switch› ‹/Switch›
При необходимости для реализации потребуется обернуть его вокруг компонентов Route
. При посещении пути URL-адреса допускается отображение только первого <Route>
, соответствующего пути.
Ранее у нас была проблема с /
рендерингом Home
компонента и других путей. Если мы создадим путь /hello/goodmorning
, что будет? Будут визуализированы компоненты пути /hello
и /hello/goodmorning
. Switch снова поможет в этом случае, выбрав только один маршрут для рендеринга, но самый важный маршрут должен быть организован так, чтобы он шел первым.
Используя Switch
, мы можем избежать того, что происходит на изображении выше, но только для URL, отличных от /
. exact={true}
обрабатывает это за /
. Помните, что Switch
выберет только первое совпадение Route
. Давайте поработаем и посмотрим на результат.
<Switch> <Route exact path="/" component={Home} /> <Route path="/hello" component={Hello} /> <Route path="/hello/goodmorning" render={() => { return <h1>Goodmorning</h1> }} /> <Route path="/books" component={Books} /> </Switch>
Кроме того, Switch
позволяет нам указать маршрут для отображения, если URL-адрес не соответствует местоположению. Для этого маршрута оставьте опору path
пустой.
// Just an example. Don't implement. This catch-all Route would be at the bottom if implemented.
<Route component={NoMatch
} />
Таким образом, Switch
сделает следующее:
- Избегайте инклюзивного рендеринга маршрута.
- включите всеобъемлющий маршрут в нижней части нашего контейнера Switch.
# 2 Вложенная маршрутизация
Помните, что мы могли визуализировать компоненты через Route
inline или указав компонент:
<Route component={SomeComponent}/>
Or
<Route render={() => { return <h1>Soemthing</h1> }/>
Компоненту, который будет создан с помощью Route
, автоматически будут переданы следующиеprop
объекты:
- соответствие
- место нахождения
- история
Мы рассмотрим только использование match
, поскольку он полезен для реализации вложенных маршрутов. Объект match
содержит следующие свойства:
- params - (объект) пары ключ / значение, извлеченные из URL-адреса, соответствующего динамическим сегментам пути.
- isExact - (логическое) true, если был найден весь URL (без завершающих символов).
- путь - (строка) шаблон пути, используемый для сопоставления. Полезно для построения вложенных ‹Route› s
- url - (строка) совпавшая часть URL-адреса. Полезно для построения вложенных ‹Link› s
Мы хотим добавить новые маршруты в маршрут /book
. Это будут книги:
- HTML
- CSS
- Реагировать
Перейдите во вторую подпапку 02-nested-routing
на вашем терминале и запустите npm install
.
В редакторе кода откройте BookComponent.js
и измените:
const Books = ({ match }) => { return ( <div> <div className="jumbotron"> <h1 className="display-3">My Books</h1> </div> <div className="container"> <div className="row"> <div className="col-md-3"> <ul> <li><Link to="">HTML</Link></li> <li><Link to="">CSS</Link></li> <li><Link to="">React</Link></li> </ul> </div> <div className="col-md-9"> {/* place routes here */} </div> </div> </div> </div> ); }
Давайте установим React Router через NPM. Открыв папку в вашем терминале, запустите:
npm install react-router-dom
Синтаксически мы продемонстрировали, что объект match
передается как props
. Помните, что используемые классы предназначены для того, чтобы стили Bootstrap вступили в силу. Не забудьте импортировать все компоненты React Router после импорта React:
import React from 'react'; import { BrowserRouter as Router, Route, Link, Switch, Redirect } from 'react-router-dom';
Нам не нужно было импортировать их все, но мы все равно это сделали. Разместите маршруты:
<Route path="" render={() => { return <h1>HTML by Ducket book</h1> }}/> <Route path="" render={() => { return <h1>CSS by Racheal Andrews</h1> }}/> <Route path="" render={() => { return <h1>React by Fullstack.io book</h1> }}/>
Мы используем рендеринг встроенных компонентов, чтобы сэкономить время. Теперь давайте заполним to=""
из Link
и path=""
из Route
.
Сделайте эти изменения:
<div className="col-md-3"> <ul> <li><Link to={`${match.url}/html`}>HTML</Link></li> <li><Link to={`${match.url}/css`}>CSS</Link></li> <li><Link to={`${match.url}/react`}>React</Link></li> </ul> </div> <div className="col-md-9"> <Route path={`${match.path}/html`} render={() => { return <h1>HTML by Ducket book</h1> }}/> <Route path={`${match.path}/css`} render={() => { return <h1>CSS by Racheal Andrews</h1> }}/> <Route path={`${match.path}/react`} render={() => { return <h1>React by Fullstack.io book</h1> }}/> </div>
${match.url}
оценивается как /books
, а ${match.path}
оценивается как localhost://3000/books.
. Используемые обратные тики - это способ объединения строк, содержащих переменные, в ES6.
Сохраните его, запустите npm start
и просмотрите работающее приложение.
# 3 Вложенная маршрутизация с параметрами пути
Любой URL-адрес, заканчивающийся на _120 _, _ 121_ или /:whatever
, указывает, что эта часть является динамически сгенерированной частью URL-адреса, которая может иметь любое значение.
Мы можем получить доступ к таким частям через match.params.id
для использования в маршрутизации.
Снова откройте третью подпапку 03-nested-routing-with-path-parameters
в вашем терминале и запустите npm install
.
Кроме того, давайте установим React Router через NPM. Открыв папку в вашем терминале, запустите:
npm install react-router-dom
Чтобы проиллюстрировать, как параметры пути могут использоваться для маршрутизации, вставьте следующее в Book.js
:
import React from 'react'; import { BrowserRouter as Router, Route, Link, Switch, Redirect } from 'react-router-dom'; const Books = ({ match }) => { return ( <div> <div className="jumbotron"> <h1 className="display-3">My Books</h1> </div> <div className="container"> <div className="row"> <div className="col-md-3"> <ul> <li><Link to={`${match.url}/html`}>HTML</Link></li> <li><Link to={`${match.url}/css`}>CSS</Link></li> <li><Link to={`${match.url}/react`}>React</Link></li> </ul> </div> <div className="col-md-9"> <Route path={`${match.path}/html`} render={() => { return <h1>HTML by Ducket book</h1> }}/> <Route path={`${match.path}/css`} render={() => { return <h1>CSS by Racheal Andrews</h1> }}/> <Route path={`${match.path}/react`} render={() => { return <h1>React by Fullstack.io book</h1> }}/> <Route path={`${match.path}/:id`} component={Child} /> </div> </div> </div> </div> ); } const Child = ({ match }) => ( <div> <h3>URL ID parameter: {match.params.id}</h3> </div> ); export default Books;
Запустите npm start
.
# 4 Маршрутизация защищенного пути
Этот вид маршрутизации предназначен для страниц веб-сайта, которым требуется, чтобы пользователь вошел в систему и прошел аутентификацию перед просмотром таких страниц. Примером может служить страница администратора .
Для обработки защищенных путей нам понадобится <Redirect/>
(стандартный компонент) и <PrivateRoute/>
(пользовательский компонент).
<PrivateRoute/>
не является стандартным <Route/>
компонентом. Стандартный компонент маршрута, предоставляемый React Router, - это<Route/>
. Мы определим <PrivateRoute/>
как наш собственный <Route/>
.
Пользовательские маршруты необходимы, когда нам нужно принять решение, нужно ли отображать <Route/>
интересующий нас объект. Как вы увидите в коде, мы перечислим <PrivateRoute/>
вместе с другими <Route/>
.
Компонент ‹Redirect /›
Визуализация ‹Redirect› приведет к переходу в новое место. Новое местоположение переопределит текущее местоположение в стеке истории, как это делают перенаправления на стороне сервера (HTTP 3xx).
<Redirect/>
имеет несколько свойств, но мы будем использовать свойство объекта to
следующим образом:
<Redirect to={{ pathname: '/login', state: { from: props.location } }}/>
При использовании это перенаправляет на путь /login
. Информация о последнем местоположении перед выполнением перенаправления будет доступна компоненту LoginPage
через this.props.location.state
.
Перейдите к последней подпапке 04-authenticated-routing
. Запустите npm install
.
Установите React Router через NPM. Открыв папку в вашем терминале, запустите:
npm install react-router-dom
Откройте App.js
и добавьте новый элемент списка /admin
к существующим.
<ul> <li><Link to="/hello">Hello</Link></li> <li><Link to="/about">About</Link></li> <li> <Link to="/books">Books</Link> </li> <li> <Link to="/admin">Admin</Link> </li> </ul>
Добавьте маршруты <PrivateRoute/>
и /login
к группе существующих <Route/>
s.
<Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/hello" component={Hello} /> <Route path="/books" component={Books} /> <Route path="/login" component={Login}/> <PrivateRoute authed={fakeAuth.isAuthenticated} path="/admin" component={Admin} /> </Switch>
Теперь создайте компонент <PrivateRoute/>
вне компонента App
:
const PrivateRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={props => ( fakeAuth.isAuthenticated ? ( <Component {...props}/> ) : ( <Redirect to={{ pathname: '/login', state: { from: props.location } }}/> ) )}/> )
<PrivateRoute/>
в конечном итоге отобразит компонент <Route>
. Компонент <Route>
использует троичную операцию для определения того, что отображать, в зависимости от того, вошел ли пользователь в систему или нет: <Redirect/>
на страницу входа или Admin
компонент страницы.
Создайте компонент Admin
:
const Admin = () => { return ( <div className="jumbotron"> <h3 className="display-3">Admin Access granted</h3> </div> ); }
Также создайте компонент Login
:
class Login extends React.Component { constructor() { super(); this.state = { redirectToReferrer: false } // binding 'this' this.login = this.login.bind(this); } login() { fakeAuth.authenticate(() => { this.setState({ redirectToReferrer: true }) }) } render() { const { from } = this.props.location.state || { from: { pathname: '/' } } const { redirectToReferrer } = this.state; if (redirectToReferrer) { return ( <Redirect to={from} /> ) } return ( <div className="jumbotron"> <h1 className="display-3">Login required</h1> <p className="lead">You must log in to view the page at {from.pathname}.</p> <p className="lead"> <a className="btn btn-primary btn-lg" onClick={this.login} role="button">Login</a> </p> </div> ) } } /* A fake authentication function */ export const fakeAuth = { isAuthenticated: false, authenticate(cb) { this.isAuthenticated = true setTimeout(cb, 100) }, }
Этот Login
компонент реализует функцию фальшивой аутентификации, которая устанавливает для пользователя вход в систему или выход из нее.
Запускаем npm start
и видим работающее приложение.
На этом мы подошли к концу статьи. Слава вам, если вы зашли так далеко. Если вы хотите получить более подробную информацию о React Router, просмотрите Документацию.
Если вам нужна завершенная версия кода, посетите завершенную ветку на Github.
Не стесняйтесь поддерживать меня (devapparel.co) и хорошо выглядеть при этом. Также прокомментируйте или поделитесь этим сообщением. Спасибо за прочтение!
Изначально опубликовано в Zeolearn Blog.