├── 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 |
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 | | Title |
83 | Read |
84 |
85 |
86 | {books}
87 |
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 |
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 | | Title |
83 | Read |
84 |
85 |
86 | {books}
87 |
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;
--------------------------------------------------------------------------------