├── README.md ├── hapi ├── app.js ├── package.json ├── index.js └── views │ └── index.jsx └── express ├── app.js ├── package.json ├── index.js └── views └── index.jsx /README.md: -------------------------------------------------------------------------------- 1 | # react-example 2 | 3 | More info: http://blog.yld.io/2015/06/10/getting-started-with-react-and-node-js/ 4 | -------------------------------------------------------------------------------- /hapi/app.js: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | var Books = require('./views/index.jsx'); 3 | 4 | var books = JSON.parse(document.getElementById('initial-data').getAttribute('data-json')); 5 | React.render(, document.getElementById('container')); -------------------------------------------------------------------------------- /express/app.js: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | var Books = require('./views/index.jsx'); 3 | 4 | var books = JSON.parse(document.getElementById('initial-data').getAttribute('data-json')); 5 | React.render(, document.getElementById('container')); -------------------------------------------------------------------------------- /express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-example-express", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "dependencies": { 6 | "body-parser": "^1.12.4", 7 | "express": "^4.12.4", 8 | "node-jsx": "^0.13.3", 9 | "react": "^0.13.3", 10 | "browserify": "^13.0.0", 11 | "reactify": "^1.1.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /hapi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-example-express", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "dependencies": { 6 | "body-parser": "^1.12.4", 7 | "browserify": "^10.2.4", 8 | "express": "^4.12.4", 9 | "hapi": "^8.6.1", 10 | "node-jsx": "^0.13.3", 11 | "react": "^0.13.3", 12 | "reactify": "^1.1.1", 13 | "through2-map": "^1.4.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /express/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var browserify = require('browserify'); 3 | var React = require('react'); 4 | var jsx = require('node-jsx'); 5 | var app = express(); 6 | 7 | jsx.install(); 8 | 9 | 10 | var Books = require('./views/index.jsx'); 11 | 12 | app.use('/bundle.js', function(req, res) { 13 | res.setHeader('content-type', 'application/javascript'); 14 | browserify('./app.js', { 15 | debug: true 16 | }) 17 | .transform('reactify') 18 | .bundle() 19 | .pipe(res); 20 | }); 21 | 22 | app.use('/', function(req, res) { 23 | var books = [{ 24 | title: 'Professional Node.js', 25 | read: false 26 | }, { 27 | title: 'Node.js Patterns', 28 | read: false 29 | }]; 30 | 31 | res.setHeader('Content-Type', 'text/html'); 32 | res.end(React.renderToStaticMarkup( 33 | React.DOM.body( 34 | null, 35 | React.DOM.div({ 36 | id: 'container', 37 | dangerouslySetInnerHTML: { 38 | __html: React.renderToString(React.createElement(Books, { 39 | books: books 40 | })) 41 | } 42 | }), 43 | React.DOM.script({ 44 | 'id': 'initial-data', 45 | 'type': 'text/plain', 46 | 'data-json': JSON.stringify(books) 47 | }), 48 | React.DOM.script({ 49 | src: '/bundle.js' 50 | }) 51 | ) 52 | )); 53 | }); 54 | 55 | var server = app.listen(3333, function() { 56 | var addr = server.address(); 57 | console.log('Listening @ http://%s:%d', addr.address, addr.port); 58 | }); -------------------------------------------------------------------------------- /hapi/index.js: -------------------------------------------------------------------------------- 1 | var Hapi = require('hapi'); 2 | var browserify = require('browserify'); 3 | var map = require('through2-map'); 4 | var fs = require('fs'); 5 | var React = require('react'); 6 | var jsx = require('node-jsx'); 7 | 8 | jsx.install(); 9 | 10 | var Books = require('./views/index.jsx'); 11 | 12 | var server = new Hapi.Server(); 13 | server.connection({ 14 | host: 'localhost', 15 | port: (process.argv[2] || 3333) 16 | }); 17 | 18 | 19 | server.route({ 20 | method: 'GET', 21 | path:'/bundle.js', 22 | handler: function (request, reply) { 23 | reply(null, browserify('./app.js') 24 | .transform('reactify') 25 | .bundle().pipe(map({ 26 | objectMode: false 27 | }, function(chunk) { 28 | return chunk; 29 | }))); 30 | } 31 | }); 32 | 33 | server.route({ 34 | method: 'GET', 35 | path:'/', 36 | handler: function (request, reply) { 37 | var books = [{ 38 | title: 'Professional Node.js', 39 | read: false 40 | }, { 41 | title: 'Node.js Patterns', 42 | read: false 43 | }]; 44 | 45 | reply(null, React.renderToStaticMarkup( 46 | React.DOM.body( 47 | null, 48 | React.DOM.div({ 49 | id: 'container', 50 | dangerouslySetInnerHTML: { 51 | __html: React.renderToString(React.createElement(Books, { 52 | books: books 53 | })) 54 | } 55 | }), 56 | React.DOM.script({ 57 | 'id': 'initial-data', 58 | 'type': 'text/plain', 59 | 'data-json': JSON.stringify(books) 60 | }), 61 | React.DOM.script({ 62 | src: '/bundle.js' 63 | }) 64 | ) 65 | )).header('Content-Type', 'text/html'); 66 | } 67 | }); 68 | 69 | server.start(function () { 70 | console.info("Listening @", server.info.uri); 71 | }); -------------------------------------------------------------------------------- /express/views/index.jsx: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | 3 | var BookForm = React.createClass({ 4 | propTypes: { 5 | onBook: React.PropTypes.func.isRequired 6 | }, 7 | getInitialState: function() { 8 | return { 9 | title: '', 10 | read: false 11 | }; 12 | }, 13 | changeTitle: function(ev) { 14 | this.setState({ 15 | title: ev.target.value 16 | }); 17 | }, 18 | changeRead: function() { 19 | this.setState({ 20 | read: !this.state.read 21 | }); 22 | }, 23 | addBook: function(ev) { 24 | ev.preventDefault(); 25 | 26 | this.props.onBook({ 27 | title: this.state.title, 28 | read: this.state.read 29 | }); 30 | 31 | this.setState({ 32 | title: '', 33 | read: false 34 | }); 35 | }, 36 | render: function() { 37 | return ( 38 |
39 |
40 | 41 |
42 |
43 |
44 | 45 |
46 |
47 |
48 | 49 |
50 |
51 | ); 52 | } 53 | }); 54 | 55 | var Books = React.createClass({ 56 | propTypes: { 57 | books: React.PropTypes.array 58 | }, 59 | getInitialState: function() { 60 | return { 61 | books: (this.props.books || []) 62 | }; 63 | }, 64 | onBook: function(book) { 65 | this.state.books.push(book); 66 | 67 | this.setState({ 68 | books: this.state.books 69 | }); 70 | }, 71 | render: function() { 72 | var books = this.state.books.map(function(book) { 73 | return ; 74 | }); 75 | 76 | return ( 77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | {books} 87 |
TitleRead
88 |
89 | ); 90 | } 91 | }); 92 | 93 | var Book = React.createClass({ 94 | propTypes: { 95 | title: React.PropTypes.string.isRequired, 96 | read: React.PropTypes.bool.isRequired 97 | }, 98 | getInitialState: function() { 99 | return { 100 | title: this.props.title, 101 | read: this.props.read 102 | }; 103 | }, 104 | handleChange: function(ev) { 105 | this.setState({ 106 | read: !this.state.read 107 | }); 108 | }, 109 | render: function() { 110 | return ( 111 | 112 | {this.props.title} 113 | 114 | 115 | ); 116 | } 117 | }); 118 | 119 | module.exports = Books; -------------------------------------------------------------------------------- /hapi/views/index.jsx: -------------------------------------------------------------------------------- 1 | var React = require('react'); 2 | 3 | var BookForm = React.createClass({ 4 | propTypes: { 5 | onBook: React.PropTypes.func.isRequired 6 | }, 7 | getInitialState: function() { 8 | return { 9 | title: '', 10 | read: false 11 | }; 12 | }, 13 | changeTitle: function(ev) { 14 | this.setState({ 15 | title: ev.target.value 16 | }); 17 | }, 18 | changeRead: function() { 19 | this.setState({ 20 | read: !this.state.read 21 | }); 22 | }, 23 | addBook: function(ev) { 24 | ev.preventDefault(); 25 | 26 | this.props.onBook({ 27 | title: this.state.title, 28 | read: this.state.read 29 | }); 30 | 31 | this.setState({ 32 | title: '', 33 | read: false 34 | }); 35 | }, 36 | render: function() { 37 | return ( 38 |
39 |
40 | 41 |
42 |
43 |
44 | 45 |
46 |
47 |
48 | 49 |
50 |
51 | ); 52 | } 53 | }); 54 | 55 | var Books = React.createClass({ 56 | propTypes: { 57 | books: React.PropTypes.array 58 | }, 59 | getInitialState: function() { 60 | return { 61 | books: (this.props.books || []) 62 | }; 63 | }, 64 | onBook: function(book) { 65 | this.state.books.push(book); 66 | 67 | this.setState({ 68 | books: this.state.books 69 | }); 70 | }, 71 | render: function() { 72 | var books = this.state.books.map(function(book) { 73 | return ; 74 | }); 75 | 76 | return ( 77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | {books} 87 |
TitleRead
88 |
89 | ); 90 | } 91 | }); 92 | 93 | var Book = React.createClass({ 94 | propTypes: { 95 | title: React.PropTypes.string.isRequired, 96 | read: React.PropTypes.bool.isRequired 97 | }, 98 | getInitialState: function() { 99 | return { 100 | title: this.props.title, 101 | read: this.props.read 102 | }; 103 | }, 104 | handleChange: function(ev) { 105 | this.setState({ 106 | read: !this.state.read 107 | }); 108 | }, 109 | render: function() { 110 | return ( 111 | 112 | {this.props.title} 113 | 114 | 115 | ); 116 | } 117 | }); 118 | 119 | module.exports = Books; --------------------------------------------------------------------------------