這一節將使用 Flux 模式與後台串接。這一章是 Node.js Fullstack 初學者的重要里程碑:
- 從 jQuery AJAX 到 MVC
- 再由 MVC 到 Flux
這節將製作一個簡單的 HTML5 前端,並模式接受來自 Node.js 的 WebSocket 資料推送。前端的製作將使用 React.js 與 Flux 模式,而不是 jQuery。
先安裝 react-websocket-view
模式:
npm install react-websocket-view --save
再根據以下步驟為 React 元件加入 WebSocket 能力:
-
Import
WebsocketView
fromreact-websocket-view
-
Use
<WebsocketView />
as the parent component, and put Websocket server URI toserver
props. -
Add
onMessage
callback to your elements.
以下範例示如何與 wss://wot.city/object/testman/viewer
連接,並將使用常用的 <p>
HTML5 元素,來接受 real-time data push。主要的重點是實戶 onMessage
callback。
import React from 'react';
import { render } from 'react-dom';
import { WebsocketView } from 'react-websocket-view';
render(
<WebsocketView
server="wss://wot.city/object/testman/viewer">
<p onMessage={function(data) {console.log(data)}}></p>
</WebsocketView>,
document.getElementById('content')
);
如果是多個 HTML5 元素呢?例如二個 <p>
元素:
<WebsocketView
server="wss://wot.city/object/testman/viewer">
<p onMessage={function(data) {console.log(data)}}></p>
<p onMessage={function(data) {console.log(data)}}></p>
</WebsocketView>
如果是多個 WebSocket 來源呢?例如二個 <p>
元素,分別接收不同的二個資料來源:
<div>
<WebsocketView
server="wss://wot.city/object/room1/viewer">
<p onMessage={function(data) {console.log(data)}}></p>
</WebsocketView>
<WebsocketView
server="wss://wot.city/object/room2/viewer">
<p onMessage={function(data) {console.log(data)}}></p>
</WebsocketView>
</div>
實現 WebSocket React 元件的項目模板。你可以用這模板製作具 WebSocket 功能的元件,或是為現有的元件注入 WebSocket 功能。使用 Flux 模式。安裝說明:
$ git clone https://github.com/jollen/react-websocket-biolerplate.git
$ cd react-websocket-biolerplate
$ npm install
$ gulp compile
使用瀏覽器開啟 dist/index.html
文件即可,你會看到來自 wot.city
服務器的即時數據。
- 如果要修改服務器來源,請開啟
src/App.jsx
,並修改server
prop - 修改完成後,必須運行
gulp compile
命令重新編譯文件
編譯相關命令:
gulp build
:將src
目錄下的 *.jsx 文件編譯為 *.jsgulp app
:將src/App.js
文件 browserify 為dist/App.js
gulp compile
:等於以上二個命令
開發相關命令:
gulp watch
:監聽所有的 *.jsx 文件,文件修改時,會自動調用gulp compile
命令gulp browser
:瀏覽器 Live Reload 功能,會自動開啟dist/index.html
文件
說明 React 元件加入 WebSocket 協定的做法:以接收來自 WebSocket 服務器的數據推送。幾個要先知道的觀念:
- 使用
react-websocket-flux
模組,這是一個簡單 Flux 實現 - 註冊事件函數到
react-websocket-flux
裡後,透過onMessage
接收即時數據 - 建議了解 Flux 模式中 Store 的用途
只需要三分鐘就能學會 react-websocket-biolerplate
的使用:
- 引入
react-websocket-biolerplate
的WebsocketStore
與WebsocketActions
- 在 React 元件的 constructor 裡調用
WebsocketActions.connect()
與 WebSocket 服務器建立連線 - 在 React 元件裡實現
onMessage
事件回調函數 - 在 React 元件的
componentDidMount
lifecycle 裡調用WebsocketStore.addMessageListener
註冊onMessage
callback - 在 React 元件的
componentWillUnmount
lifecycle 裡調用WebsocketStore.removeMessageListener
解除註冊
完整範例代碼位於 src/Component.jsx
。
以下是完整的實現步驟說明。根據此,也能為現有的 React 元件注入 WebSocket 功能。
import React, { Component } from 'react';
import { render } from 'react-dom';
// 1. 引入 'react-websocket-flux'
import { WebsocketStore, WebsocketActions } from 'react-websocket-flux';
export class MyComponent extends Component {
constructor(props, context) {
super(props, context);
// 2. 初始化 this.state
this.state = {
temperature: -1
};
// 3. WebSocket 的 'onMessage' callback
this.onMessage = this.onMessage.bind(this);
// 4. 連線到 WebSocket Server
WebsocketActions.connect(this.props.server);
}
componentDidMount() {
// 5. 將 'onMessage' 註冊到 react-websocket-flux
WebsocketStore.addMessageListener(this.onMessage);
}
componentWillUnmount() {
// 將 'onMessage' 從 react-websocket-flux 解除註冊
WebsocketStore.removeMessageListener(this.onMessage);
}
onMessage(data) {
// 6. Deserialize: 從 Server 推送過來的 JSON data 取出資料,並放入 this.state
this.setState({
temperature: data.temperature
});
console.log(data)
}
render() {
return (
<div>
<h1>{this.state.temperature}</h1>
</div>
);
}
}
完成後編譯元件:
$ gulp compile
編譯好的文件位於 src/Component.js
:你可以開始在 React 應用程式裡使用此元件了。在 React 應用程式裡,引入你的元件使用:
- 加入
server
prop 指定 WebSocket 服務器 URI - 可以使用本專案提供的
wss://wot.city/object/testman/viewer
測試數據
範例片斷如下:
// 我的 React 元件
import { MyComponent } from './Component';
// 加入 server prop
render(
<MyComponent server="wss://wot.city/object/testman/viewer">
</MyComponent>,
document.getElementById('content')
);
完整範例請參考 src/App.jsx
。