├── .gitignore ├── README.md ├── css └── base.css ├── index.html ├── package.json ├── scripts ├── CommentBox.jsx └── example.jsx ├── server.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | node_modules 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OUT OF DATE 2 | 3 | **This example is no longer maintained. Check out [React Hot Loader starter kits](https://github.com/gaearon/react-hot-loader/tree/master/docs#starter-kits) instead. For the most minimal example, see [React Hot Boilerplate](https://github.com/gaearon/react-hot-boilerplate).** 4 | 5 | 6 | # About this fork 7 | 8 | This is a fork of react-tutorial that supports live editing via **[react-hot-loader](https://github.com/gaearon/react-hot-loader)**. 9 | This means you can edit `CommentBox.jsx` after running the server, and it will update without reload. 10 | 11 | -------------------- 12 | 13 | # React comment box example 14 | 15 | This is the React comment box example from [the React tutorial](http://facebook.github.io/react/docs/tutorial.html). 16 | 17 | ## To use 18 | 19 | ``` 20 | npm install 21 | node server.js 22 | ``` 23 | 24 | And visit http://localhost:3000/. Try opening multiple tabs! 25 | -------------------------------------------------------------------------------- /css/base.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #fff; 3 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;; 4 | font-size: 15px; 5 | line-height: 1.7; 6 | margin: 0; 7 | padding: 30px; 8 | } 9 | 10 | a { 11 | color: #4183c4; 12 | text-decoration: none; 13 | } 14 | 15 | a:hover { 16 | text-decoration: underline; 17 | } 18 | 19 | code { 20 | background-color: #f8f8f8; 21 | border: 1px solid #ddd; 22 | border-radius: 3px; 23 | font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace; 24 | font-size: 12px; 25 | margin: 0 2px; 26 | padding: 0px 5px; 27 | } 28 | 29 | h1, h2, h3, h4 { 30 | font-weight: bold; 31 | margin: 0 0 15px; 32 | padding: 0; 33 | } 34 | 35 | h1 { 36 | border-bottom: 1px solid #ddd; 37 | font-size: 2.5em; 38 | font-weight: bold; 39 | margin: 0 0 15px; 40 | padding: 0; 41 | } 42 | 43 | h2 { 44 | border-bottom: 1px solid #eee; 45 | font-size: 2em; 46 | } 47 | 48 | h3 { 49 | font-size: 1.5em; 50 | } 51 | 52 | h4 { 53 | font-size: 1.2em; 54 | } 55 | 56 | p, ul { 57 | margin: 15px 0; 58 | } 59 | 60 | ul { 61 | padding-left: 30px; 62 | } 63 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello React 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-tutorial", 3 | "version": "0.0.0", 4 | "description": "Code from the React tutorial.", 5 | "main": "server.js", 6 | "dependencies": { 7 | "body-parser": "^1.6.6", 8 | "cors": "^2.4.1", 9 | "express": "^4.8.6", 10 | "jquery": "^1.11.1", 11 | "react": "^0.11.0" 12 | }, 13 | "devDependencies": { 14 | "jsx-loader": "^0.11.0", 15 | "react-hot-loader": "^0.4.2", 16 | "webpack": "^1.4.0-beta1", 17 | "webpack-dev-server": "^1.5.0" 18 | }, 19 | "scripts": { 20 | "test": "echo \"Error: no test specified\" && exit 1", 21 | "start": "node server.js" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/reactjs/react-tutorial.git" 26 | }, 27 | "keywords": [ 28 | "react", 29 | "tutorial", 30 | "comment", 31 | "example" 32 | ], 33 | "author": "petehunt", 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "https://github.com/reactjs/react-tutorial/issues" 37 | }, 38 | "homepage": "https://github.com/reactjs/react-tutorial" 39 | } 40 | -------------------------------------------------------------------------------- /scripts/CommentBox.jsx: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 3 | var Showdown = require('showdown'), 4 | $ = require('jquery'), 5 | React = require('react'), 6 | converter = new Showdown.converter(); 7 | 8 | var Comment = React.createClass({ 9 | render: function() { 10 | var rawMarkup = converter.makeHtml(this.props.children.toString()); 11 | return ( 12 |
13 |

14 | {this.props.author} 15 |

16 | 17 |
18 | ); 19 | } 20 | }); 21 | 22 | var CommentBox = React.createClass({ 23 | loadCommentsFromServer: function() { 24 | $.ajax({ 25 | url: this.props.url, 26 | dataType: 'json', 27 | success: function(data) { 28 | this.setState({data: data}); 29 | }.bind(this), 30 | error: function(xhr, status, err) { 31 | console.error(this.props.url, status, err.toString()); 32 | }.bind(this) 33 | }); 34 | }, 35 | handleCommentSubmit: function(comment) { 36 | var comments = this.state.data; 37 | comments.push(comment); 38 | this.setState({data: comments}, function() { 39 | // `setState` accepts a callback. To avoid (improbable) race condition, 40 | // `we'll send the ajax request right after we optimistically set the new 41 | // `state. 42 | $.ajax({ 43 | url: this.props.url, 44 | dataType: 'json', 45 | type: 'POST', 46 | data: comment, 47 | success: function(data) { 48 | this.setState({data: data}); 49 | }.bind(this), 50 | error: function(xhr, status, err) { 51 | console.error(this.props.url, status, err.toString()); 52 | }.bind(this) 53 | }); 54 | }); 55 | }, 56 | getInitialState: function() { 57 | return {data: []}; 58 | }, 59 | componentDidMount: function() { 60 | this.loadCommentsFromServer(); 61 | setInterval(this.loadCommentsFromServer, this.props.pollInterval); 62 | }, 63 | render: function() { 64 | return ( 65 |
66 |

Comments

67 | 68 | 69 |
70 | ); 71 | } 72 | }); 73 | 74 | var CommentList = React.createClass({ 75 | render: function() { 76 | var commentNodes = this.props.data.map(function(comment, index) { 77 | return ( 78 | // `key` is a React-specific concept and is not mandatory for the 79 | // purpose of this tutorial. if you're curious, see more here: 80 | // http://facebook.github.io/react/docs/multiple-components.html#dynamic-children 81 | 82 | {comment.text} 83 | 84 | ); 85 | }); 86 | return ( 87 |
88 | {commentNodes} 89 |
90 | ); 91 | } 92 | }); 93 | 94 | var CommentForm = React.createClass({ 95 | handleSubmit: function(e) { 96 | e.preventDefault(); 97 | var author = this.refs.author.getDOMNode().value.trim(); 98 | var text = this.refs.text.getDOMNode().value.trim(); 99 | if (!text || !author) { 100 | return; 101 | } 102 | this.props.onCommentSubmit({author: author, text: text}); 103 | this.refs.author.getDOMNode().value = ''; 104 | this.refs.text.getDOMNode().value = ''; 105 | return; 106 | }, 107 | render: function() { 108 | return ( 109 |
110 | 111 | 112 | 113 |
114 | ); 115 | } 116 | }); 117 | 118 | module.exports = CommentBox; -------------------------------------------------------------------------------- /scripts/example.jsx: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 3 | var CommentBox = require('./CommentBox'), 4 | React = require('react'); 5 | 6 | React.renderComponent( 7 | , 8 | document.getElementById('content') 9 | ); 10 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | var app = express(); 4 | var webpack = require('webpack'); 5 | var WebpackDevServer = require('webpack-dev-server'); 6 | var config = require('./webpack.config'); 7 | var cors = require('cors'); 8 | 9 | var comments = [{author: 'Pete Hunt', text: 'Hey there!'}, 10 | {author: 'Justin Gordon', text: 'Aloha from @railsonmaui'} 11 | ]; 12 | 13 | app.use(bodyParser.json()); 14 | app.use(bodyParser.urlencoded({extended: true})); 15 | app.use(cors()); 16 | 17 | app.get('/comments.json', function(req, res) { 18 | res.setHeader('Content-Type', 'application/json'); 19 | res.send(JSON.stringify(comments)); 20 | }); 21 | 22 | app.post('/comments.json', function(req, res) { 23 | comments.push(req.body); 24 | res.setHeader('Content-Type', 'application/json'); 25 | res.send(JSON.stringify(comments)); 26 | }); 27 | 28 | app.listen(3001); 29 | 30 | new WebpackDevServer(webpack(config), { 31 | publicPath: config.output.publicPath, 32 | hot: true 33 | }).listen(3000, 'localhost', function (err, result) { 34 | if (err) { 35 | console.log(err); 36 | } 37 | 38 | console.log('Listening at localhost:3000'); 39 | }); 40 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | 3 | module.exports = { 4 | entry: [ 5 | 'webpack-dev-server/client?http://localhost:3000', 6 | 'webpack/hot/dev-server', 7 | './scripts/example' 8 | ], 9 | output: { 10 | path: __dirname, 11 | filename: 'bundle.js', 12 | publicPath: '/scripts/' 13 | }, 14 | plugins: [ 15 | new webpack.HotModuleReplacementPlugin() 16 | ], 17 | resolve: { 18 | extensions: ['', '.js', '.jsx'] 19 | }, 20 | module: { 21 | loaders: [ 22 | { test: /\.jsx$/, loaders: ['react-hot', 'jsx'] }, 23 | ] 24 | }, 25 | externals: { 26 | 'showdown': 'window.Showdown' 27 | } 28 | }; --------------------------------------------------------------------------------