От автора: при создании приложений React одна вещь, которую разработчики не любят использовать — это маршрутизация, обычно из-за предполагаемой сложной кривой обучения. В этой статье мы собираемся развенчать этот миф и показать вам, как легко реализовать маршрутизацию и обслуживать гибкие маршруты в ваших приложениях с помощью React Router 4.
Если упрощенно, гибкая маршрутизация в основном обслуживает различные маршруты для пользователей на основе окна просмотра их устройства. Для этого обычно используются медиа-запросы CSS. Единственная проблема заключается в том, что при медиа-запросах вы можете показывать или не показывать разные элементы с помощью реквизитов CSS. Благодаря гибким маршрутам вы теперь можете обслуживать отдельные представления приложений React для разных пользователей, основываясь непосредственно на их размерах экрана.
Что мы будем создавать
В этом руководстве мы рассмотрим, как создать простое приложение панели пользователя, которое обслуживает разные маршруты для пользователей в зависимости от размера экрана их устройства.
Ресурсы
Чтобы следовать этому руководству, вам понадобится следующее:
NodeJS, установленный на вашей машине
NPM, установленный на вашей машине
Чтобы проверить установку, выполните следующую команду:
1 2 |
node --version npm --version |
Если в качестве результата вы получите номера версий пакетов, все в порядке.
Приступаем к работе
Установка React
В этой статье мы будем использовать React, который должен быть установлен на вашем компьютере. Чтобы установить React, выполните следующую команду:
1 |
npm install -g create-react-app |
После того, как вы успешно установили React на свой компьютер, мы можем продолжить создание нового приложения, выполнив команду:
1 2 |
create-react-app responsive-routing cd responsive-routing |
Следующее, что вам нужно сделать, это установить необходимые модули, которые нужны, чтобы успешно создать эту демо-версию. Это: react-router-dom и react-media. Мы устанавливаем их, запустив команду:
1 |
npm install react-router-dom react-media |
Теперь мы можем запустить приложение, выполнив команду:
1 |
npm start |
Создание компонента навигации
Логотип Github в центре страницы будет выполнять роль навигационной части нашего приложения. Давайте посмотрим, как это сделать. В папке src/ создайте новую папку с именем Nav, а в ней следующие файлы:
1 2 |
mkdir Nav cd Nav && touch index.js Nav.css |
Вам нужно добавить логотип Github и сохранить его, как logo.svg.
Теперь обновите файл src/Nav/index.js, чтобы он выглядел следующим образом:
1 2 3 4 5 6 7 8 9 10 |
// src/Nav/index.js import React from 'react'; import './Nav.css'; import logo from './logo.svg'; const Nav = () => ( <nav> <img src={logo} alt="" /> </nav> ); export default Nav; |
Компонент навигации имеет следующиеt стили:
1 2 3 4 5 6 7 8 9 10 11 12 |
/** src/Nav/Nav.css **/ nav { display: flex; justify-content: center; height: 50px; margin-bottom: 10px; } nav > img { display: block; width: 50px; height: auto; } |
Теперь давайте визуализируем компонент Nav. Для этого мы отредактируем файл src/App.js по умолчанию, чтобы он выглядел следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// src/App.js import React, { Component } from 'react'; import Nav from './Nav'; = App extends Component { render() { return ( <div> <Nav /> </div> ); } } export default App; |
Теперь, когда мы запускаем приложение, используя npm start и переходим в браузер, мы получаем следующее:
Создание карточек пользователя
Карточки пользователя отвечают за отображение информации о пользователе. Теперь давайте посмотрим, как их создать. В папке src/ приложения создайте новую папку Users, а в ней следующие файлы:
1 2 |
mkdir Users cd Users && touch UsersCard.js UsersCard.css |
Измените файл UsersCard.js следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// src/Users/UsersCard.js import React from 'react'; import {Link} from 'react-router-dom'; import './UsersCard.css' const UsersCard = ({ user, match }) => <Link to={`${match.url}/${user.id}`} className="column card"> <img src={user.avatar} alt=""/> <p className="users-card__name">{user.name}</p> <p className="users-card__username">@{user.username}</p> <div className="users-card__divider"></div> <div className="users-card__stats"> <div> <p>{user.followers}</p> <span>Followers</span> </div> <div> <p>{user.following}</p> <span>Following</span> </div> <div> <p>{user.repos}</p> <span>Repositories</span> </div> </div> </Link>; export default UsersCard; |
Если вы обратите внимание на фрагмент кода выше, мы использовали компонент Link из agent-router-dom, чтобы предоставить возможность просматривать данные пользователя при клике на карточке. Таким образом, для данной карточки пользователя с идентификатором 10009 и компонентом Link будет генерироваться такой URL: //your-app/current-page/10009
//your-app/current-page представляет существующий URL-адрес
10009 представляет идентификатор пользователя.
Вся эта информация будет передаваться при визуализации компонента. Компонент имеет следующие стили:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/** src/Nav/UsersCard.css **/ .card { border-radius: 2px; background-color: #ffffff; box-shadow: 0 1.5px 3px 0 rgba(0, 0, 0, 0.05); max-width: 228px; margin: 10px; display: flex; flex-direction: column; align-items: center; padding: 0; } .card img { width: 50px; height: auto; border-radius: 50%; display: block; padding: 15px 0; } .users-card__name { font-weight: 400; font-size: 16.5px; line-height: 1.19; letter-spacing: normal; text-align: left; color: #25292e; } .users-card__username { font-size: 14px; color: #707070; } .users-card__divider { border: solid 0.5px #efefef; width: 100%; margin: 15px 0; } .users-card__stats { display: flex; } .users-card__stats p { font-size: 20px; } .users-card__stats div { margin: 10px; text-align: center; } .users-card__stats span { color: #707070; font-size: 12px; } |
Список всех пользователей
То, что мы видим выше — это список пользователей. Чтобы наше приложение выглядело так, нам нужно сначала создать компонент UsersList. В каталоге src/Users создайте следующие файлы:
1 |
touch UsersList.js UsersList.css |
Чтобы отобразить карточки пользователей в вышеуказанном формате, нам нужно проделать большую работу — но не беспокойтесь, я буду вашим гидом.
Давайте отредактируем UsersList.js следующим образом. Во-первых, мы выполняем импорт:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// src/Users/UsersList.js import React from 'react'; import UsersCard from './UsersCard'; import './UsersList.css'; const listOfUsersPerRow = (users, row, itemsPerRow, match) => users .slice((row - 1) * itemsPerRow, row * itemsPerRow) .map(user => <UsersCard user={user} key={user.id} match={match} />); const listOfRows = (users, itemsPerRow, match) => { const numberOfUsers = users.length; const rows = Math.ceil(numberOfUsers / itemsPerRow); return Array(rows) .fill() .map((val, rowIndex) => ( <div className="columns"> {listOfUsersPerRow(users, rowIndex + 1, itemsPerRow, match)} </div> )); }; //... |
Функции listOfUsersPerRow и listOfRows обеспечивают, чтобы в каждой строке у нас было не больше карточек, чем указано. Следующее, что нужно сделать — это использовать функции для создания списка пользователей следующим образом
1 2 3 4 5 6 7 8 9 |
//src/Users/UsersList.js //... const UsersList = ({ users, itemsPerRow = 2, match }) => ( <div className="cards"> <h3 className="is-size-3 has-text-centered">Users</h3> {listOfRows(users, itemsPerRow, match)} </div> ); export default UsersList; |
UsersList.css будет выглядеть так:
1 2 3 4 5 6 7 |
/** src/Users/UsersList.css **/ .cards { margin-left: 20px; } .columns { margin-top: 0; } |
Создание представления информации пользователя
При нажатии на карточку пользователя из списка пользователей, отображается одна карточка пользователя. Давайте посмотрим, как создать этот компонент. Создайте следующие файлы в каталоге src/Users:
1 |
touch UsersDetails.js UsersDetails.css |
Теперь добавим следующее в файл UsersDetails.js:
1 2 3 4 5 6 7 8 |
/ src/Users/UsersDetails.js import React from 'react'; import UsersCard from './UsersCard'; const UsersDetails = ({ user, match }) => <div> <h3 className="is-size-3 has-text-centered">Details</h3> <UsersCard user={user} match={match} /> </div>; export default UsersDetails; |
Создание компонента панели пользователей
Компонент панели пользователей прост. Мы отображаем UserList и при нажатии на карточку выводим сбоку экрана информацию без необходимости перезагрузки страницы. Давайте рассмотрим, как это реализовать. Создайте файл UsersDashboard.js в каталоге Users:
1 |
touch UserDashboard.js |
Измените UserDashboard.js следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
// src/Users/UsersDashboard.js import React from 'react'; import { Route } from 'react-router-dom'; import UsersList from './UsersList'; import UsersDetails from './UsersDetails'; const UsersDashboard = ({ users, user, match }) => ( <div className="columns"> <div className="column"> <UsersList users={users} match={match} /> </div> <div className="column"> <Route path={match.url + '/:id'} render={props => ( <UsersDetails user={ users.filter( user => user.id === parseInt(props.match.params.id, 10) )[0] } match={match} /> )} /> </div> </div> ); export default UsersDashboard; |
В приведенном выше примере мы использовали компонент Route, предоставляемый компонентом response-router-dom в качестве компонента для отображения информации конкретного пользователя при клике на карточке. Теперь давайте объединим все это. Обновите файл src/App.js, чтобы он выглядел следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
// src/App.js import React, { Component } from 'react'; import { Route, Redirect } from 'react-router-dom'; import Nav from './Nav'; import UsersList from './Users/UsersList'; import UsersDetails from './Users/UsersDetails'; import UsersDashboard from './Users/UsersDashboard'; import './App.css'; class App extends Component { state = { users: [ { id: 39191, avatar: '//avatars0.githubusercontent.com/u/39191?v=4', name: 'Paul Irish', username: 'paulirish', followers: '12k', following: '1k', repos: '1.5k' }, //... other user data ] }; render() { return ( <div className="App"> <Nav /> <Route path="/dashboard" render={props => ( <UsersDashboard users={this.state.users} {...props} /> )} /> <Redirect from="/" to="/dashboard"/> <Redirect from="/users" to="/dashboard"/> </div> ); } } export default App; |
Когда мы перейдем в браузер, мы получим следующее:
Обратите внимание на разницу в URL-адресе, когда отображаются данные пользователя
Адаптивная маршрутизация
Все становится интереснее, когда пользователи посещают это приложение, независимо от размера экрана, они получают тот же вид и функционал. В реальных приложениях полезно предоставлять пользователю оптимальный опыт, и один из способов сделать это — обслуживать представления, в точности соответствующие их размерам устройства. Теперь мы рассмотрим, как это сделать в нашем приложении.
При посещении приложения на широком экране пользователь перенаправляется к маршруту приложения /dashboard, а при просмотре на меньшем экране пользователь должен быть направлен к маршруту приложения /users. Давайте посмотрим, как это сделать.
Обновите файл src/App.js, чтобы он выглядел следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
// src/App.js import React, { Component } from 'react'; import { Route, Switch, Redirect } from 'react-router-dom'; import Media from 'react-media'; import Nav from './Nav'; import UsersList from './Users/UsersList'; import UsersDetails from './Users/UsersDetails'; import UsersDashboard from './Users/UsersDashboard'; import './App.css'; class App extends Component { //set application state [...] render() { return ( <div className="App"> <Nav /> <Media query="(max-width: 599px)"> {matches => matches ? ( <Switch> <Route exact path="/users" render={props => ( <UsersList users={this.state.users} {...props} /> )} /> <Route path="/users/:id" render={props => ( <UsersDetails user={ this.state.users.filter( user => user.id === parseInt(props.match.params.id, 10) )[0] } {...props} /> )} /> <Redirect from="/" to="/users"/> <Redirect from="/dashboard" to="/users"/> </Switch> ) [...] |
В приведенном выше фрагменте мы используем компонент Media, чтобы установить размер экрана. Если ширина экрана меньше 599 пикселей, мы устанавливаем набор, который хотим отобразить для разных маршрутов, а также перенаправляем маршруты / и /dashboard к маршруту /users.
Теперь, если размер экрана больше 599 пикселей, мы отображаем полную панель пользователя, как мы это делали ранее
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// src/App.js [...] : ( <Switch> <Route path="/dashboard" render={props => ( <UsersDashboard users={this.state.users} {...props} /> )} /> <Redirect from="/" to="/dashboard"/> <Redirect from="/users" to="/dashboard"/> </Switch> ) } </Media> </div> ); } } export default App; |
Теперь, когда мы посещаем приложение, оно будет работать следующим образом:
На этом этапе мы можем видеть, что гораздо лучше обслуживать разные маршруты на основе размеров экрана, чем использовать только медиа-запросы, потому что теперь вы можете обслуживать специально разработанные компоненты для пользователей на основе их размеров устройств.
Заключение
В этой статье мы рассмотрели введение в компонентную маршрутизацию с помощью React и как реализовать условный рендеринг в приложениях React. Вот ссылка на полный репозиторий Github. Вы можете оставить комментарий или предложение ниже.
Автор: Chris Nwamba
Источник: //scotch.io/
Редакция: Команда webformyself.