Статьи

Создание совместного веб-приложения с помощью PubNub, React.js и ES6

В моих предыдущих уроках я демонстрировал, как создавать прототипы устройств Интернета вещей , а также создавал визуализации данных с помощью аппаратных датчиков , используя сеть потоков данных PubNub . В этом руководстве я собираюсь показать вам, как использовать PubNub для создания веб-приложения для совместной работы в реальном времени с использованием React.js , который позволяет очень эффективно управлять DOM, и JavaScript следующего поколения, ES6 .

Веб-приложение PubNub Reactjs Stickie

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 в реальном времени. Здесь вы будете создавать общие заметки. Это пользовательский поток приложения:

  1. Пользователь входит в систему.
  2. Как только пользователь вводит имя, приложение получает последние 50 заметок, если таковые имеются.
  3. Пользователь что-то печатает на стикере и нажимает клавишу возврата для подтверждения.
  4. Новая заметка-стикер отображается вместе с другими заметками в вашем браузере, а также в любом другом браузере всех пользователей, которые в данный момент находятся в сети.

Теперь давайте начнем!

  • реагировать
    Современные веб-приложения с React и Redux
    Эндрю Берджесс

В каталоге вашего приложения запустите 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 будет следить за изменениями вашего файла и автоматически перестроит ваш выходной файл.

Включите скрипт 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 будет вставлено.

Вы можете запустить свой сервер 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-страница) работает там.

Откройте новый файл 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, который браузеры могут отображать очень хорошо.

С помощью 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)];
Сервер localhost спрашивает ваше имя

Хотя здесь я использую диалоговое окно с приглашением браузера, в действительности я рекомендую вам создать еще один компонент пользовательского интерфейса с функциями входа в систему или использовать сторонний компонент диалогового окна. Вы можете найти множество компонентов многократного использования, таких как модальный элемент Elemental и диалоговое окно Material UI.

Теперь вы собираетесь использовать 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, и все другие пользователи получат сообщение одновременно (в течение ¼ с!).

Пользовательский интерфейс приложения состоит из нескольких компонентов пользовательского интерфейса, которые выглядят так:

Компоненты PubNub Stickie в приложении React

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! Я надеюсь, вам понравился урок!

PubNub Stickie приложение GIF-анимация

Вы можете просмотреть весь код, включая CSS, в этом репозитории GitHub . Хотя в этом уроке я использовал «облегченную» версию app-lite.jsx , вы можете взглянуть на app.jsx для получения дополнительных возможностей.

Если вы заинтересованы в создании большего количества приложений реального времени, таких как приложения чата, многопользовательские игры, торговые приложения и т. Д., Перейдите на PubNub и найдите больше ресурсов!

У нас есть курс, направленный на то, чтобы максимально развить ваши навыки React. В этом курсе вы начнете создавать современные веб-приложения с использованием React и Redux. Начиная с нуля, вы будете использовать эти две библиотеки для создания полноценного веб-приложения.

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

Заинтересованы? Проверьте это!

  • PubNub : глобальная сеть потоков данных в реальном времени для IoT, мобильных и веб-приложений
  • PubNub JavaScript SDK Учебное пособие
  • React : библиотека JavaScript для создания пользовательских интерфейсов
  • ES6 : спецификация языка ECMAScript 2015
  • Веб-пакет : Модуль Builder