В моих предыдущих уроках я демонстрировал, как создавать прототипы устройств Интернета вещей , а также создавал визуализации данных с помощью аппаратных датчиков , используя сеть потоков данных PubNub . В этом руководстве я собираюсь показать вам, как использовать PubNub для создания веб-приложения для совместной работы в реальном времени с использованием React.js , который позволяет очень эффективно управлять DOM, и JavaScript следующего поколения, ES6 .
Live Demo: Совместные стикеры
Я создал две версии одного и того же приложения Stickie Note: одна, которую я размещал в этом CodePen, использует версии React для CDN, а другая — на GitHub с использованием менеджеров пакетов. В этом уроке я использую «облегченную» версию последнего. Я расскажу, как создать приложение, используя все вкусности: npm, webpack, Babel для JSX и ES6!
Предпосылки
Чтобы следовать, вам нужно:
- базовое понимание React
- опыт работы с менеджером пакетов npm для загрузки, установки и управления зависимостями
- опыт работы с модулем сборки веб-пакетов , для объединения JavaScript и других ресурсов для браузера (работает аналогично grunt или gulp)
- Node.js и npm установлены на вашем компьютере
Этот урок не охватывает, как начать работу с React. Тем не менее, вы можете узнать больше из многих других превосходных учебных пособий Envato Tuts + .
Что вы собираетесь делать
Вы собираетесь создать простое веб-приложение, используя PubNub. PubNub — это сеть потоков данных (DSN), которая предоставляет глобальную инфраструктуру, которая позволяет легко создавать и масштабировать приложения и устройства IoT в реальном времени. Здесь вы будете создавать общие заметки. Это пользовательский поток приложения:
- Пользователь входит в систему.
- Как только пользователь вводит имя, приложение получает последние 50 заметок, если таковые имеются.
- Пользователь что-то печатает на стикере и нажимает клавишу возврата для подтверждения.
- Новая заметка-стикер отображается вместе с другими заметками в вашем браузере, а также в любом другом браузере всех пользователей, которые в данный момент находятся в сети.
Теперь давайте начнем!
Установка пакетов
В каталоге вашего приложения запустите npm init
чтобы настроить файл package.json, а затем установите эти модули.
Установите модуль модуля webpack , который компилирует, объединяет, минимизирует и сжимает статические ресурсы для интерфейса:
$ npm install webpack --save-dev
Установите веб-сервер webpack для запуска локального сервера:
$ npm install webpack-dev-server --save-dev
Установите дополнения React, React DOM и CSS для анимации:
$ npm install react react-dom react-addons-css-transition-group --save
Установите Babel для использования JSX и ES6. Мы собираемся написать с ES6 (ES 2015), который является JavaScript следующего поколения, с помощью Babel, компилятора:
$ sudo npm install babel-loader babel-core babel-preset-es2015 babel-preset-react --save
Установите PubNub для связи в реальном времени:
$ npm install pubnub --save
Настройте структуру приложения и веб-сервер
Создайте структуру своего приложения, подобную этой:
01
02
03
04
05
06
07
08
09
10
11
|
├── /app
│ ├── app.jsx
│ ├── stickie.jsx
│ ├── stickieList.jsx
├── /dist
├── /css
├── /images
├── /node_modules
├── index.html
├── package.json
└── webpack.config.js
|
И настройте webpack.config.js :
1
2
3
4
5
6
7
|
var webpack = require(‘webpack’);
module.exports = {
entry: ‘./app/app.jsx’,
output: {path: ‘./dist’, filename: ‘bundle.js’},
watch: true,
module: {…}
}
|
Смотрите весь конфигурационный файл на этом репозитории GitHub .
По сути, вы задаете файл ввода (файл верхнего уровня) и место назначения вывода, где все ваши файлы js (и .jsx) будут объединены в один файл после запуска команды webpack. Также, установив watch: true
, вы гарантируете, что webpack будет следить за изменениями вашего файла и автоматически перестроит ваш выходной файл.
Создание файла index.html
Включите скрипт bundle.js в ваш файл index.html:
01
02
03
04
05
06
07
08
09
10
11
12
|
<!DOCTYPE html>
<html>
<head>
<meta charset=»utf-8″>
<title>Collaborative Stickies</title>
<link rel=»stylesheet» href=»css/style.css» />
</head>
<body>
<section id=»container»></section>
<script src=»dist/bundle.js»></script>
</body>
</html>
|
Также обратите внимание на элемент с id=”container”
в теле. Здесь ваше приложение React будет вставлено.
Запущен Webpack Dev Server
Вы можете запустить свой сервер Dev с помощью команды,
$ ./node_modules/.bin/webpack-dev-server
Или вы можете установить его в свой package.json, добавив эту строку:
1
2
3
|
«scripts»: {
«start»: «webpack-dev-server»
},
|
Так что вы можете запустить сервер с помощью команды npm start
.
В вашем браузере перейдите по адресу http: // localhost: 8080 / webpack-dev-server / , и вы увидите, что ваше приложение (пока пустая HTML-страница) работает там.
Создание компонентов React с ES6
Откройте новый файл app.jsx в каталоге приложения, настроенный для точки входа в вашем webpack.config.js . Как видно из расширения файла, мы будем использовать расширение синтаксиса JSX JavaScript.
Сначала импортируйте модули и файлы, необходимые для app.jsx :
1
2
3
4
|
import React from ‘react’;
import ReactDOM from ‘react-dom’;
import StickieList from ‘./stickieList’;
import ‘pubnub’;
|
Оператор импорта, недавно введенный в ES6, используется для импорта функций, объектов или примитивов, которые были экспортированы из внешнего модуля или скрипта.
Затем определите класс CollabStickies
, который расширяет класс React.Component
, используя это объявление класса ES6. Это эквивалентно методу React.createClass с ES5:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
class CollabStickies extends React.Component {
constructor(props) {
super(props);
this.state = {
stickieList: []
}
}
componentWillMount() {
… // will explain later
}
…
render() {
return (
<div>
<StickieWritable username={this.props.username} color={this.props.color} />
<StickieList stickieList={this.state.stickieList} />
</div>
);
}
}
|
В функции конструктора вы устанавливаете начальное состояние этих изменяемых данных, массив stickieList
. Мы будем обновлять массив каждый раз, когда получаем новую заметку, используя this.setState()
.
В функции рендеринга используйте JSX для определения виртуальных элементов DOM, подобных шаблонам HTML. В этом случае пользовательские компоненты StickieWritable
и StickieList
включены. Вы можете передавать изменяемые реквизиты и состояния компонентам для использования. Мы собираемся определить их позже.
Когда вы создаете приложение, Babel будет транслировать весь этот синтаксис ES6 и JSX в ES5, который браузеры могут отображать очень хорошо.
Рендеринг узла DOM с привязкой данных
С помощью ReactDOM.render()
, который поставляется с пакетом react-dom
, визуализируйте компонент CollabStickies
на узле DOM в своем HTML.
1
2
3
4
|
ReactDOM.render(
<CollabStickies username={username} color={color} />,
document.getElementById(‘container’)
);
|
Здесь вы заметили имя пользователя и цвет props
. Эти данные используются для компонента CollabStickies
и передаются его дочерним компонентам.
Значения должны быть получены из логина пользователя; однако, чтобы упростить приложение для этого упражнения, давайте просто воспользуемся простым window.prompt()
для получения имени пользователя, а затем дадим случайный цвет заметок при загрузке приложения.
1
2
3
4
|
var username = window.prompt(‘Your name’);
const colors = [‘yellow’, ‘pink’, ‘green’, ‘blue’, ‘purple’];
var color = colors[~~(Math.random() * colors.length)];
|
Хотя здесь я использую диалоговое окно с приглашением браузера, в действительности я рекомендую вам создать еще один компонент пользовательского интерфейса с функциями входа в систему или использовать сторонний компонент диалогового окна. Вы можете найти множество компонентов многократного использования, таких как модальный элемент Elemental и диалоговое окно Material UI.
Использование PubNub для совместной работы
Теперь вы собираетесь использовать PubNub для совместной работы приложения.
PubNub — это глобально распределенная сеть потоков данных, которая позволяет легко создавать приложения в реальном времени. Его основная функция, pub / sub, отправляет и получает данные между несколькими пользователями одновременно.
В этом приложении любой, кто «вошел в систему», может публиковать сообщения в заметках и делиться ими с другими пользователями.
Чтобы использовать PubNub в своем приложении, убедитесь, что модуль pubnub был установлен и импортирован в начало файла.
Инициализация PubNub
Во-первых, вам нужно инициализировать его, чтобы создать экземпляр объекта Pubnub. Вам нужны ключи API во время создания экземпляра, поэтому, пожалуйста, зарегистрируйтесь в PubNub, чтобы получить свои собственные ключи.
01
02
03
04
05
06
07
08
09
10
11
|
const publish_key = ‘pub-c-1d17120…’;
const subscribe_key = ‘sub-c-85bdc…’;
const pubnub = require(‘pubnub’).init({
publish_key : publish_key,
subscribe_key : subscribe_key,
ssl: true,
uuid: username
});
const channel = ‘stickie-notes’;
|
Здесь вы назначаете имя пользователя, полученное в процессе входа в систему, в качестве уникального идентификатора uuid
. (В этом упражнении мы принимаем любую строку, введенную пользователем, как uuid, но в действительности вам нужна настоящая система входа в систему, чтобы каждый uuid был действительно уникальным, без дублирования!)
Также обратите внимание, что я использую объявление const
ES6 вместо var
для этих глобальных постоянных значений. В ES6 const
действует как переменная только для чтения и представляет постоянную ссылку на значение. В последнем примере вы также увидите недавно введенное let
, которое является локальной переменной области видимости блока.
Подписка на сообщения
Чтобы создать приложение общих заметок, вы будете использовать метод pubNub publish()
чтобы отправлять свои заметки всем, в то время как subscribe()
позволяет другим пользователям получать все заметки. Метод subscribe()
вызывается автоматически каждый раз, когда кто-то публикует новую заметку.
В вашем приложении React давайте вызовем subscribe()
в componentWillMount()
, который вызывается непосредственно перед тем, как начальный рендеринг происходит в жизненном цикле приложения.
1
2
3
4
5
6
7
8
|
componentWillMount() {
pubnub.subscribe({
channel: channel,
restore: true,
connect: () => this.connect(),
message: (m) => this.success(m)
});
}
|
Метод подписки является асинхронным, и когда каждая операция успешно завершается, вызывается обратный вызов message
. При обратном вызове давайте обновим список заметок, установив состояние массива stickieList
, которое было определено в конструкторе в начале.
В React изменение ваших данных с помощью setState
автоматически обновляет представление.
1
2
3
4
|
success(m) {
let newList = [m].concat(this.state.stickieList);
this.setState({stickieList: newList});
}
|
Мы создадим представление (компонент пользовательского интерфейса) позже.
В обратных вызовах подписки вы, вероятно, заметили забавный синтаксис со стрелками =>
. Это называется функциями стрелок, синтаксис которых короче, чем у выражений функций ES5. Кроме того, это выражение лексически связывает значение this
. Опять же, с Babel, мы можем использовать все удивительные ES6!
Кроме того, мы используем необязательный обратный вызов connect
для метода подписки для извлечения «истории». Он будет извлекать прошлые данные, когда соединение с PubNub установлено впервые.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
connect() {
pubnub.history({
channel: channel,
count: 50,
callback: (m) => {
m[0].reverse();
for (var v of m[0]) {
let newList = this.state.stickieList.concat(v);
this.setState({stickieList: newList});
}
}
});
}
|
history()
является частью функции хранения и воспроизведения PubNub, и в этом случае она получает последние 50 сообщений из PubNub. При success
stickieList
обновите представление, установив здесь состояние массива stickieList
.
Публикация сообщений
Давайте создадим класс StickieWritable
. Это компонент заметки, который принимает пользовательский ввод.
Это выглядит так:
1
2
3
4
5
6
7
|
render() {
return (
<div className={‘stickie-note writable ‘ + this.props.color}>
<textarea type=’text’ placeholder=’Your new note…’ onKeyUp={this.handleTextChange.bind(this)} />
</div>
);
}
|
В textarea
слушайте событие onKeyUp
, и каждый раз, когда событие вызывается, handleTextChange
функцию handleTextChange
чтобы проверить, является ли ключ ключом возврата / ввода. Обратите внимание, что я связываю это при вызове функции. В отличие от React.createClass()
, который является методом React ES5 для создания класса, класс ES6 не привязывает методы автоматически к экземпляру объекта, поэтому вам нужно связать его самостоятельно. (Есть несколько разных способов достижения одного и того же.)
В функции handleTextChange
опубликуйте текст и пользовательские данные в PubNub:
01
02
03
04
05
06
07
08
09
10
11
12
|
var data = {
username: this.props.username,
color: this.props.color,
text: e.target.value,
timestamp: Date.now()
};
pubnub.publish({
channel: channel,
message: data,
callback: e.target.value = » // resetting the text field
});
|
Теперь, когда пользователь набирает текст в блокноте и нажимает клавишу возврата, сообщение будет отправлено в PubNub, и все другие пользователи получат сообщение одновременно (в течение ¼ с!).
Создание компонентов пользовательского интерфейса
Пользовательский интерфейс приложения состоит из нескольких компонентов пользовательского интерфейса, которые выглядят так:
1. CollabStickies
2. StickieWritable
3. Stickie
4. StickieList
О компонентах 1 и 2 уже позаботились, поэтому давайте создадим компонент 3, отдельный компонент заметки.
Создайте новый файл stickie.jsx для визуализации пользовательского интерфейса с использованием JSX. В отличие от компонента StickieWritable
, это компонент пользовательского интерфейса, доступный только для чтения, без функциональности UX. Он имеет только функцию render()
для рисования заметки с текстом, используя данные проп.
По сути, каждый раз, когда пользователь получает новое сообщение от другого пользователя, сообщение отображается в новом липком компоненте.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
import React from ‘react’;
import ReactDOM from ‘react-dom’;
export default class Stickie extends React.Component {
render() {
return (
<div className={‘stickie-note ‘ + this.props.color} >
<p className=’note’>{this.props.text}</p>
<p className=’username’>{this.props.username}</p>
</div>
);
}
}
|
Далее мы собираемся создать другой компонент пользовательского интерфейса, stickieList.jsx , который является контейнером для этого компонента и содержит кучу заметок вместе.
Анимационные компоненты
Импортируйте Stickie.jsx и все другие зависимости в StickieList.jsx . Здесь я использую дополнение ReactCSSTransitionGroup
и собственный веб-шрифт.
1
2
3
4
5
|
import React from ‘react’;
import ReactDOM from ‘react-dom’;
import ReactCSSTransitionGroup from ‘react/lib/ReactCSSTransitionGroup’;
import Stickie from ‘./stickie’;
import webfontloader from ‘webfontloader’
|
Вы можете установить загрузчик веб-шрифтов с помощью npm:
$ npm install webfontloader
Затем вы можете загрузить любые пользовательские шрифты на ваш выбор. Вы можете взглянуть на исходный код, чтобы увидеть, как импортируется пользовательский шрифт Google.
В render()
используйте функцию стрелки ES6 и map()
для итерации массива и используйте stickieList
для рендеринга каждого только что созданного вами компонента Stickie:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
export default class StickieList extends React.Component {
render() {
let items = (this.props.stickieList || []).map((item) =>
<li key={item.username + ‘-‘ + item.timestamp} >
<div className=»stickieWrapper»>
<Stickie text={item.text} color={item.color} username={item.username}/>
</div>
</li>);
return (
<ReactCSSTransitionGroup transitionName=’animation’ transitionEnterTimeout={500} transitionLeaveTimeout={500} component=’ul’ id=»stickiesList»>
{items}
</ReactCSSTransitionGroup>
)
}
}
|
Определенные компоненты могут быть анимированы с помощью <ReactCSSTransitionGroup>
. Установите значение transitionName
, которое необходимо использовать в CSS для определения стиля анимации. Также обратите внимание на ключевой атрибут в <li>
. Вам необходимо использовать уникальный ключ для каждого списка, чтобы анимировать каждый компонент, когда вы используете <ReactCSSTransitionGroup>
.
React добавляет дополнительные имена классов. Например, когда ваш transitionName
имеет значение « animation
», у вас также будут « animation-enter
», « animation-enter-active
», « animation-leave
» и « animation-leave-active
».
Вот код в /css/style.css:
01
02
03
04
05
06
07
08
09
10
|
.animation-enter {
opacity: 0.1;
transform: scale(1.3);
transition: all 1s ease-out;
}
.animation-enter.animation-enter-active {
opacity: 1;
transform: scale(1);
}
…
|
Теперь вы только что создали приложение для совместной работы в реальном времени с React и PubNub! Я надеюсь, вам понравился урок!
Вы можете просмотреть весь код, включая CSS, в этом репозитории GitHub . Хотя в этом уроке я использовал «облегченную» версию app-lite.jsx , вы можете взглянуть на app.jsx для получения дополнительных возможностей.
Если вы заинтересованы в создании большего количества приложений реального времени, таких как приложения чата, многопользовательские игры, торговые приложения и т. Д., Перейдите на PubNub и найдите больше ресурсов!
Хотите больше реагировать?
У нас есть курс, направленный на то, чтобы максимально развить ваши навыки React. В этом курсе вы начнете создавать современные веб-приложения с использованием React и Redux. Начиная с нуля, вы будете использовать эти две библиотеки для создания полноценного веб-приложения.
Вы начнете с самой простой архитектуры и постепенно создадите приложение, функция за функцией. Вы узнаете об основных понятиях, таких как инструменты, редукторы и маршрутизация. Вы также узнаете о некоторых более продвинутых методах, таких как умные и немые компоненты, чистые компоненты и асинхронные действия. К концу вы создадите полноценное приложение для изучения карточек с интервальным повторением.
Заинтересованы? Проверьте это!
Ссылки
- PubNub : глобальная сеть потоков данных в реальном времени для IoT, мобильных и веб-приложений
- PubNub JavaScript SDK Учебное пособие
- React : библиотека JavaScript для создания пользовательских интерфейсов
- ES6 : спецификация языка ECMAScript 2015
- Веб-пакет : Модуль Builder