| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 | let Comment = React.createClass({  rawMarkup: function () {    let rawMarkup = marked(this.props.children.toString(), { sanitize: true });    return { __html: rawMarkup };  },  render: function () {    return (      <div className="comment">        <h2 className="commentAuthor">          {this.props.author}        </h2>        <span dangerouslySetInnerHTML={this.rawMarkup()} />      </div>    );  }});let CommentList = React.createClass({  render: function () {    let commentNodes = this.props.data.map(function (comment) {      return (        <Comment author={comment.author} key={comment.id}>          {comment.text}        </Comment>      );    });    return (      <div className="commentList">        {commentNodes}        </div>    );  }});let CommentForm = React.createClass({  getInitialState: function () {    return {      author: "",      text: ""    };  },  handleAuthorChange: function (e) {    this.setState({ author: e.target.value });  },  handleSubmit: function (e) {    e.preventDefault();    let author = this.state.author.trim();    let text = this.state.text.trim();    if (!text || !author) {      return;    }    this.props.onCommentSubmit({ author: author, text: text });    this.setState({ author: '', text: '' });  },  handleTextChange: function (e) {    this.setState({ text: e.target.value });  },  render: function () {    return (      <div className="commentForm">        <form className="commentForm" onSubmit={this.handleSubmit}>          <input            type="text"            placeholder="Your name"            value={this.state.author}            onChange={this.handleAuthorChange}          />          <input            type="text"            placeholder="Say something..."            value={this.state.text}            onChange={this.handleTextChange}          />          <input type="submit" value="Post" />        </form>      </div>    );  }});let CommentBox = React.createClass({  componentDidMount: function () {    this.loadCommentsFromServer();    setInterval(this.loadCommentsFromServer, this.props.pollInterval);  },  getInitialState: function () {    return { data: [] };  },  handleCommentSubmit: function (comment) {    let comments = this.state.data;    // Optimistically set an id on the new comment. It will be replaced by an    // id generated on the server. In a production application, you would likely    // not use Date.now() for this and would have a more robust system in place.    comment.id = Date.now();    let newComments = comments.concat([comment]);    // Assume all will go well.    this.setState({ data: newComments });    $.ajax({      url: this.props.url,      dataType: "json",      type: "POST",      data: comment,      success: function (data) {        this.setState({ data: data });      }.bind(this),      error: function (xhr, status, err) {        // Restore the original comment state since the new state could not be applied.        this.setState({data: comments });        console.error(this.props.url, status, err.toString());      }    });  },  loadCommentsFromServer: function () {    $.ajax({      url: this.props.url,      dataType: "json",      cache: false,      success: function (result) {        this.setState({ data: result });      }.bind(this),      error: function (xhr, status, err) {        console.error(this.props.url, status, err.toString());      }.bind(this)    });  },  render: function () {    return (      <div className="commentBox">        <h1>Comments</h1>        <CommentList data={this.state.data} />        <CommentForm onCommentSubmit={this.handleCommentSubmit} />        </div>    );  }});ReactDOM.render(  <CommentBox url="/api/comments" pollInterval={2000} />,  document.getElementById("content"));
 |