在我之前的教程中,我演示了如何 使用 PubNub的数据流网络创建物联网设备的原型,并 从硬件传感器创建数据可视化。在本教程中,我将向您展示如何使用 PubNub 使用react.js构建实时协作 Web 应用程序 ,它可以让您非常有效地操作dom, 以及下一代javascript ES6。
现场演示:协作贴纸
我创建了同一个 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 网络服务器以运行本地服务器:
$ 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 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>
另外,请注意正文中带有 a 的元素id=”container” 。这是你的 React 应用程序将被插入的地方。
运行 Webpack 开发服务器
您可以使用以下命令运行您的开发服务器,
$ ./node_modules/.bin/webpack-dev-server
或者您可以通过添加以下行在您的 package.json 中进行设置:
"scripts": { "start": "webpack-dev-server" },
这样您就可以使用 npm start命令运行服务器。
在您的浏览器中,转到http://localhost:8080/webpack-dev-server/,您应该会看到您的应用程序(到目前为止是一个空白的 HTML 页面)在那里运行。
使用 ES6 创建 React 组件
在 app 目录下打开一个新的 app.jsx文件,正如您在webpack.config.js中为入口点配置的那样。从文件扩展名中可以看出,我们将使用 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这等效于 React.createClassES5 的方法:
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().
在 render 函数中,使用 JSX 定义类似 HTML 模板的虚拟 DOM 元素。在这种情况下,自定义组件 StickieWritable和StickieList 被包括在内。您可以将可变道具和状态传递给要使用的组件。我们稍后会定义它们。
当你构建应用程序时,Babel 会将所有这些 ES6 和 JSX 语法转换为 ES5,浏览器可以很好地呈现。
使用数据绑定渲染 DOM 节点
With ReactDOM.render(),随 包一起提供,在 HTML 中的 DOM 节点上react-dom渲染组件。CollabStickies
ReactDOM.render( <CollabStickies username={username} color={color} />, document.getElementById('container') );
在这里,您会注意到 username 和 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 实际上都是唯一的,没有重复!)
另外,请注意我使用的是 ES6const声明,而不是var这些全局常量值。在 ES6 中,aconst充当只读变量,表示对值的常量引用。在后面的示例中,您还将看到新引入的let,它是块作用域的局部变量。
订阅消息
要创建可共享笔记应用程序,您将使用 PubNub 的 publish()方法将您的笔记发送给所有人,同时subscribe()让其他用户接收所有笔记。subscribe()每次有人发布新笔记时,都会自动调用该方法。
在您的 React 应用程序中,让我们调用 inside ,它subscribe()在componentWillMount()应用程序生命周期中初始渲染发生之前立即调用。
componentWillMount() { pubnub.subscribe({ channel: channel, restore: true, connect: () => this.connect(), message: (m) => this.success(m) }); }
subscribe 方法是async hronous,当每个操作成功完成时, 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函数检查该键是否为返回/回车键。请注意,我在调用函数时绑定了 this。与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 组件
应用程序 UI 由几个 UI 组件组成,如下所示
1. CollabStickies
2. StickieWritable
3. Stickie
4. StickieList
组件 1 和 2 已经处理好了,所以让我们创建组件 3,一个单独的便笺组件。
创建一个新文件 stickie.jsx以使用 JSX 呈现 UI。与StickieWritable组件不同,这是一个只读的 UI 组件,没有 UX 功能。它仅具有render()使用道具数据绘制带有文本的便签的功能。
基本上,每次用户收到来自另一个用户的新消息时,该消息都会呈现在一个新的 Stickie 组件中。
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插件和一个自定义的网络字体。
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>. 当您使用<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 存储库中查看整个代码,包括 CSS 。尽管在本教程中,我使用的是“lite”版本app-lite.jsx,但您可以查看app.jsx以了解更多功能。
如果您有兴趣构建更多实时应用程序,例如聊天应用程序、多人游戏、交易应用程序等,请前往PubNub并找到更多资源!
想要更多反应?
我们开设了一门课程,专门针对尽可能提高您的 React 技能。 在本课程中,您将开始使用 React 和redux构建现代 Web 应用程序。从零开始,您将使用这两个库来构建一个完整的 Web 应用程序。
您将从最简单的架构开始,然后逐个功能地慢慢构建应用程序。您将了解一些基本概念,例如工具、reducer 和路由。您还将了解一些更高级的技术,例如智能组件和哑组件、纯组件和异步操作。最后,您将创建一个完整的抽认卡应用程序,用于通过间隔重复进行学习。
- 先决条件
- 你要做什么
- 创建 index.html 文件
- 运行 Webpack 开发服务器
- 使用数据绑定渲染 DOM 节点
- 初始化 PubNub
- 订阅消息
- 发布消息
- 动画组件