React work with tornado.
I would like to understand how React.js work, so just try to do it…
Based on Ubuntu 14.04 64bit
Prerequisite : node.js, webpack, tornado, fixed-data-table.
Flow
Run Tornado -> regularly get XML data from another website -> display with React
Install
- mkdir react-table && cd react-table
- npm init
- npm install webpack –save-dev
- npm install babel-loader babel-core babel-preset-es2015 babel-preset-react –save-dev
- ln -s /usr/bin/nodejs /usr/bin/node
- npm install –save react
- npm install –save react-dom
- npm install webpack-dev-server –save-dev
- npm install fixed-data-table –save
- npm install css-loader style-loader –save-dev
React part
touch webpack.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| var path = require('path'); var webpack = require('webpack');
module.exports = { context: __dirname + "/src", entry: "./app.js", output: { filename: "app.js", path: __dirname + "/dist", }, module: { loaders: [ { test: /\.jsx?$/, include: [ __dirname + "/src" ], exclude: /node_modules/, loader: 'babel', query: { presets: ['react', 'es2015'] } }, { test: /\.css$/, loader: 'style-loader!css-loader' }, ] }, };
|
touch myTable.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
| "use strict"; var FakeObjectDataListStore = require('./dataListStore'); var FixedDataTable = require('fixed-data-table'); var React = require('react');
const {Table, Column, Cell} = FixedDataTable; const TextCell = ({rowIndex, data, col, ...props}) => ( <Cell {...props}> {data.getObjectAt(rowIndex)[col]} </Cell> ); class MyLinkCell extends React.Component { render() { const {rowIndex, data, col, ...props} = this.props; const link = data.getObjectAt(rowIndex)[col]; return ( <Cell {...props}> <a href={link}>{link}</a> </Cell> ); } } class DataListWrapper { constructor(indexMap, data) { this._indexMap = indexMap; this._data = data; } getSize() { return this._indexMap.length; } getObjectAt(index) { return this._data.getObjectAt( this._indexMap[index] ); } } class MyTable extends React.Component { constructor(props) { super(props); var pageData = JSON.parse(document.getElementById('page-data').getAttribute('data-page')); this._dataList = new FakeObjectDataListStore(pageData); this.state = { filteredDataList: this._dataList, }; this._onFilterChange = this._onFilterChange.bind(this); } _onFilterChange(e) { if (!e.target.value) { this.setState({ filteredDataList: this._dataList, }); } var filterBy = e.target.value; var size = this._dataList.getSize(); var filteredIndexes = []; for (var index = 0; index < size; index++) { var {TITLE} = this._dataList.getObjectAt(index); if (TITLE.indexOf(filterBy) !== -1){ filteredIndexes.push(index); } } this.setState({ filteredDataList: new DataListWrapper(filteredIndexes, this._dataList), }); } render() { var {filteredDataList} = this.state; return ( <div> <input onChange={this._onFilterChange} placeholder="Filter by 職稱" /> <br /> <Table rowHeight={50} rowsCount={filteredDataList.getSize()} headerHeight={50} width={1000} height={500} {...this.props}> <Column header={<Cell>職稱</Cell>} cell={<TextCell data={filteredDataList} col="TITLE" />} fixed={true} width={100} /> <Column header={<Cell>用人單位</Cell>} cell={<TextCell data={filteredDataList} col="ORG_NAME" />} fixed={true} width={100} /> <Column header={<Cell>工作區域</Cell>} cell={<TextCell data={filteredDataList} col="WORK_PLACE_TYPE" />} width={100} /> <Column header={<Cell>人員區分</Cell>} cell={<TextCell data={filteredDataList} col="GENDER_TYPE" />} width={100} /> <Column header={<Cell>開始日</Cell>} cell={<TextCell data={filteredDataList} col="DATE_FROM" />} width={100} /> <Column header={<Cell>結束日</Cell>} cell={<TextCell data={filteredDataList} col="DATE_TO" />} width={100} /> <Column header={<Cell>網址</Cell>} cell={<MyLinkCell data={filteredDataList} col="VIEW_URL" />} width={400} /> </Table> </div> ); } } module.exports = MyTable;
|
touch dataListStore.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class dataListStore { constructor( rows ){ this.size = rows.length; this._cache = rows; } getObjectAt( index) { if (index < 0 || index > this.size){ console.log('_QQca -> ',this._cache[index],index); return undefined; } if (this._cache[index] === undefined) { console.log('_cache undefined!!!!! '); } return this._cache[index]; } getAll() { if (this._cache.length < this.size) { for (var i = 0; i < this.size; i++) { this.getObjectAt(i); } } return this._cache.slice(); } getSize() { return this.size; } } module.exports = dataListStore;
|
touch app.js
1 2 3 4 5 6
| import MyTable from './myTable' import React from 'react' import ReactDOM from 'react-dom' ReactDOM.render(<MyTable />,document.getElementById('example'));
|
run webpack
root@ubuntu:/home/jeff/react-table# webpack
copy app.js to Tornado part
root@ubuntu:/home/jeff/react-table# mkdir -p ../react-tornado/static/js && mkdir ../react-tornado/static/css && mkdir -p ../react-tornado/templates
root@ubuntu:/home/jeff/react-table# cp fixed-data-table.css ../react-tornado/static/css/
root@ubuntu:/home/jeff/react-table# cp ./dist/app.js ../react-tornado/static/js/
Tornado part
/react-tornado
touch /react-tornado/templates/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <!doctype html> <html> <head> <meta charset="UTF-8"> <title>Govjobs</title> <link href="/static/css/fixed-data-table.css" rel="stylesheet"> </head> <body style="font-family:arial;font-size:12px; background:#e1e1e1"> <p></p> <div id="example"></div> <div id="page-data" data-page=""></div> <script src="/static/js/app.js"></script> </body> </html>
|
touch /react-tornado/main.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
import os,json, time, datetime import tornado.httpserver import tornado.options from tornado import gen from tornado import web, ioloop, websocket
import xml.etree.cElementTree as ET from apscheduler.schedulers.background import BackgroundScheduler import urllib3
settings = { "static_path": os.path.join(os.path.dirname(__file__), "static"), "template_path": os.path.join(os.path.dirname(__file__), "templates"), "autoreload": True } class graphHandler(tornado.web.RequestHandler): @gen.coroutine def i(self): return self.loadData() @gen.coroutine def get(self): response, announceDate = yield self.i() self.render("index.html", a=response,b=announceDate) def loadData(self): module_dir = os.path.dirname(__file__) file_path = os.path.join(module_dir, 'export.xml') A=[] tree = ET.parse(file_path) root = tree.getroot() ANNOUNCE_DATE = root.find('ANNOUNCE_DATE').text for country in root.findall('ROW'): A.append({ 'TITLE' : country.find('TITLE').text, 'ORG_NAME' : country.find('ORG_NAME').text, 'WORK_PLACE_TYPE' : country.find('WORK_PLACE_TYPE').text, 'GENDER_TYPE' : country.find('GENDER_TYPE').text, 'DATE_FROM' : country.find('DATE_FROM').text, 'DATE_TO' : country.find('DATE_TO').text, 'VIEW_URL' : country.find('VIEW_URL').text }) return json.dumps(A, ensure_ascii=False),ANNOUNCE_DATE def saveData(): http = urllib3.PoolManager() r = http.request('GET', 'http://web3.dgpa.gov.tw//WANT03FRONT//AP//WANTF00003.aspx?GETJOB=Y') if r.status == 200: module_dir = os.path.dirname(__file__) file_path = os.path.join(module_dir, 'export.xml') with open(file_path, "wb") as code: code.write(r.data)
sched = BackgroundScheduler() def scheduled_job(): saveData() def main(): application = tornado.web.Application([ (r"/", graphHandler) ], **settings)
http_server = tornado.httpserver.HTTPServer(application) port = int(os.environ.get("PORT", 5000)) http_server.listen(port) sched.add_job(scheduled_job, 'cron', day_of_week='mon-fri', hour=18, minute=00) sched.start() tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": main()
|
Run
python main.py
Demo
There are troubles to get data regularly on heroku has some limits on http request and the file save…
https://govjobs.herokuapp.com/
Work fine on local