在我以前的教程中,我演示了如何对物联网设备进行原型设计 ,还使用PubNub的数据流网络从硬件传感器创建了数据可视化 。 在本教程中,我将向您展示如何使用PubNub通过React.js和下一代JavaScript ES6来构建一个实时协作Web应用程序,该应用程序可以使您非常有效地操作DOM。
现场演示: 协作便利贴
我已经创建了同一个Stickie Note应用程序的两个版本:我在此CodePen上托管的一个版本使用CDN托管的React版本,另一个在GitHub上使用包管理器。 在本教程中,我使用后者的“精简版”。 我将使用所有优点(包括npm,webpack,Babel for JSX和ES6)逐步介绍如何构建应用程序!
先决条件
要继续进行,您需要:
- 对React的基本了解
- npm软件包管理器的工作知识,可用于下载,安装和管理依赖项
- webpack模块构建器的工作知识,以便为浏览器捆绑JavaScript和其他资产(其工作方式类似于grunt或gulp)
- 您的计算机上安装了Node.js和npm
本教程不介绍如何开始使用React。 但是,您可以从许多其他出色的Envato Tuts +教程中学到更多。
你要做什么
您现在将使用PubNub构建一个简单的Web应用程序。 PubNub是一个数据流网络(DSN),它提供了一个全球基础结构,使您可以轻松构建和扩展实时应用程序和IoT设备。 在这里,您将创建可共享的“便签”。 这是应用程序的用户流:
- 用户登录。
- 用户输入名称后,应用程序将立即检索最近的50个便笺(如果有)。
- 用户在便笺本上键入内容,然后按返回键以提交。
- 新的即时贴便条将与浏览器中的其他便条以及当前在线的所有其他浏览器一起出现。
安装套件
在您应用程序的目录中,运行npm init
来设置package.json文件,然后安装这些模块。
安装webpack模块构建器,该构建器可编译,连接,缩小和压缩前端的静态资产:
$ npm install webpack --save-dev
安装webpack Web服务器以运行本地服务器:
$ 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。 我们将在编译器Babel的帮助下使用下一代JavaScript JavaScript ES6(ES 2015)进行编写:
$ sudo npm install babel-loader babel-core babel-preset-es2015 babel-preset-react --save
安装PubNub进行实时通信:
$ npm install pubnub --save
配置应用程序结构和Web服务器
创建类似于以下内容的应用程序结构:
├── /app
│ ├── app.jsx
│ ├── stickie.jsx
│ ├── stickieList.jsx
├── /dist
├── /css
├── /images
├── /node_modules
├── index.html
├── package.json
└── webpack.config.js
并配置webpack.config.js :
var webpack = require('webpack');
module.exports = {
entry: './app/app.jsx',
output: {path: './dist', filename: 'bundle.js'},
watch: true,
module: {...}
}
在此GitHub存储库上查看整个配置文件。
基本上,您要设置一个入口文件(顶级文件)和输出目的地,在您运行webpack命令之后,所有js(和.jsx)文件都将被构建到一个文件中。 另外,通过设置watch: true
,可以确保webpack监视文件更改并自动重建输出文件。
创建index.html文件
在index.html文件中包含脚本bundle.js :
<!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
您可以使用以下命令运行开发服务器:
$ ./node_modules/.bin/webpack-dev-server
或者,您可以通过添加以下行在package.json中进行设置:
"scripts": {
"start": "webpack-dev-server"
},
这样您就可以使用npm start
命令运行服务器。
在浏览器中,转到http:// localhost:8080 / webpack-dev-server / ,您应该看到其中正在运行您的应用程序(到目前为止为空白HTML页面)。
使用ES6创建React组件
在webpack.config.js中为入口点配置的应用程序目录下,打开一个新的app.jsx文件。 从文件扩展名可以看到,我们将使用JSX JavaScript语法扩展名。
首先,导入app.jsx所需的模块和文件:
import React from 'react';
import ReactDOM from 'react-dom';
import StickieList from './stickieList';
import 'pubnub';
ES6中新引入的import语句用于导入已从外部模块或脚本导出的函数,对象或基元。
然后使用此ES6类声明定义一个类CollabStickies
,该类扩展了React.Component
类。 这等效于ES5的React.createClass
方法:
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()
获得新的this.setState()
,我们都会更新数组。
在render函数中,使用JSX定义类似HTML模板的虚拟DOM元素。 在这种情况下,将包括自定义组件StickieWritable
和StickieList
。 您可以将可变的道具和状态传递给组件以使用。 我们将在以后定义它们。
在构建应用程序时,Babel会将所有这些ES6和JSX语法转换为ES5,浏览器可以很好地呈现该语法。
使用数据绑定渲染DOM节点
使用react-dom
软件包随附的ReactDOM.render()
,在HTML的DOM节点上呈现CollabStickies
组件。
ReactDOM.render(
<CollabStickies username={username} color={color} />,
document.getElementById('container')
);
在这里,您会注意到用户名和color props
。 此数据用于CollabStickies
组件,并传递到其子组件。
这些值应从用户登录名获取; 但是,为了简化此应用程序的应用程序,我们只需要使用一个简单的window.prompt()
来获取用户名,然后在加载应用程序时使用随机颜色的便笺即可。
var username = window.prompt('Your name');
const colors = ['yellow', 'pink', 'green', 'blue', 'purple'];
var color = colors[~~(Math.random() * colors.length)];
尽管实际上我在这里使用的是浏览器本机提示对话框,但实际上,我还是建议您使用登录功能创建另一个UI组件,或者使用第三方对话框组件。 您可以找到许多可重用的组件,例如Elemental UI的Modal和Material UI的Dialog 。
使用PubNub进行协作
现在,您将使用PubNub使应用程序具有协作性。
PubNub是一个全球分布的数据流网络,可让您轻松构建实时应用程序。 它的核心功能pub / sub可同时在多个用户之间发送和接收数据。
在此应用程序中,任何“登录”的人都可以在便笺上发布消息并与其他用户共享。
要在您的应用中使用PubNub,请确保已将pubnub模块安装并导入到文件顶部。
初始化PubNub
首先,您需要对其进行初始化以创建Pubnub对象的实例。 实例化期间需要API密钥,因此请注册PubNub以获得自己的密钥。
const publish_key = 'pub-c-1d17120...'; // your pub key
const subscribe_key = 'sub-c-85bdc...'; // your sub key
const pubnub = require('pubnub').init({
publish_key : publish_key,
subscribe_key : subscribe_key,
ssl: true,
uuid: username
});
const channel = 'stickie-notes';
在这里,您将从“登录”过程中获得的用户名分配为uuid
唯一标识符。 (在本练习中,我们将用户输入的任何字符串都当作uuid,但实际上,您需要一个真实的登录系统,以便每个uuid实际上都是唯一的,没有重复!)
另外,请注意,我正在使用ES6 const
声明,而不是这些全局常量值的var
。 在ES6中, const
充当只读变量,并表示对值的常量引用。 在后面的示例中,您还将看到新引入的let
,它是块作用域局部变量。
订阅消息
要创建可共享的笔记应用程序,您将使用PubNub的publish()
方法将您的笔记发送给所有人,而subscription subscribe()
允许其他用户接收所有笔记。 每当有人发布新笔记时,都会自动调用subscribe()
方法。
在您的应用程序做出反应,我们不妨将subscribe()
内componentWillMount()
在应用程序生命周期中发生的初始渲染之前被立即调用。
componentWillMount() {
pubnub.subscribe({
channel: channel,
restore: true,
connect: () => this.connect(),
message: (m) => this.success(m)
});
}
subscription方法是异步的,当每个操作成功完成时,将调用message
回调。 在回调中,让我们通过设置stickieList
数组的状态来更新便笺列表,该状态是在开始时在构造函数中定义的。
在React中,使用setState
修改数据会自动更新视图。
success(m) {
let newList = [m].concat(this.state.stickieList);
this.setState({stickieList: newList});
}
我们稍后将创建视图(UI组件)。
在订阅回调中,您可能已经注意到带有箭头=>
的有趣语法。 这称为箭头函数,其语法比ES5函数表达式短。 同样,该表达式在词法上绑定了this
值。 同样,有了Babel,我们可以利用所有ES6的强大功能!
另外,我们使用可选的connect
回调方法来订阅方法来检索“历史记录”。 首次建立与PubNub的连接时,它将获取过去的数据。
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的“ 存储和播放”功能的一部分,在这种情况下,它将从PubNub中获取最后50条消息。 在success
回调中,也通过在此处设置stickieList
数组的状态来更新视图。
发布消息
让我们创建一个类StickieWritable
。 它是一个便签组件,需要用户输入。
它呈现如下:
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
函数以检查该键是否为返回键/输入键。 请注意,在调用函数时,我要对此进行绑定。 与React.createClass()
是React的ES5创建类的方法不同,ES6类不会将方法自动绑定到对象的实例,因此您需要自己绑定它。 (实现同一件事有几种不同的方法。)
在handleTextChange
函数中,将文本和用户数据发布到PubNub:
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,所有其他用户同时(在¼秒之内!)接收到该消息。
创建UI组件
应用程序用户界面由几个用户界面组件组成,如下所示:
1. CollabStickies
2. StickieWritable
3.置顶
4. StickieList
组件1和2已经处理完毕,因此让我们创建组件3,即单个便签组件。
创建一个新文件stickie.jsx以使用JSX呈现UI。 与StickieWritable
组件不同,这是一个没有UX功能的只读UI组件。 它仅具有render()
函数,可使用prop数据使用文本绘制便签。
基本上,每次用户从另一个用户收到新消息时,该消息就会在新的粘性组件中呈现。
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>
);
}
}
接下来,我们将创建另一个UI组件stickieList.jsx ,该组件是该组件的容器,并包含一堆便笺。
动画组件
将Stickie.jsx和所有其他依赖项导入到StickieList.jsx中 。 在这里,我正在使用ReactCSSTransitionGroup
插件和自定义Web字体。
import React from 'react';
import ReactDOM from 'react-dom';
import ReactCSSTransitionGroup from 'react/lib/ReactCSSTransitionGroup';
import Stickie from './stickie';
import webfontloader from 'webfontloader'
您可以使用npm安装Web字体加载器:
$ npm install webfontloader
然后,您可以加载您选择的任何自定义字体。 您可以查看源代码,以了解如何导入自定义Google字体。
在render()
,使用ES6箭头函数和map()
迭代数组,并使用stickieList
渲染刚创建的每个Stickie组件:
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>
的key属性。 使用<ReactCSSTransitionGroup>
时,需要为每个列表使用唯一键来为每个组件设置动画。
React添加了额外的类名。 例如,当您的transitionName
为“ animation
”时,您还将具有“ animation-enter
”,“ animation-enter-active
”,“ animation-leave
”和“ animation-leave-active
”。
这是/css/style.css中的代码:
.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构建了一个实时协作应用程序! 希望您喜欢本教程!
您可以在此GitHub repo中查看整个代码,包括CSS。 尽管在本教程中,我使用的是“ lite”版本app-lite.jsx ,但您可以查看app.jsx以获得更多功能。
如果您有兴趣构建更多实时应用程序,例如聊天应用程序,多人游戏,交易应用程序等,请访问PubNub并找到更多资源!
需要更多反应吗?
我们有一门专门针对您的React技能的课程。 在本课程中 ,您将开始使用React和Redux构建现代的Web应用程序。 从零开始,您将使用这两个库来构建完整的Web应用程序。
您将从最简单的架构开始,然后逐个功能逐步构建应用程序。 您将学习基本概念,例如工具,缩减器和路由。 您还将学习一些更高级的技术,例如智能和哑组件,纯组件和异步动作。 到最后,您将创建一个完整的抽认卡应用程序,用于通过间隔重复学习。
有兴趣吗 看看这个!
参考资料
- PubNub :用于物联网,移动和Web应用程序的全球实时数据流网络
- PubNub JavaScript SDK教程
- React :一个用于创建用户界面JavaScript库
- ES6 :ECMAScript 2015语言规范
- webpack :模块生成器