Search code examples
javascriptreactjsisomorphic-javascript

Binding events handlers for React template rendered on server side


In order to get my head around React.js, I'm working on a simple noticeboard app that renders the views on both the client and server side. Unfortunately, I've hit a snag.

The file components/index.jsx currently looks like this:

var React = require('react');

var Notice = React.createClass({
  render: function () {
    return (
        <div className="noticeitem">
          {this.props.text}
        </div>
    );
  }
});

var NoticeForm = React.createClass({
  handleSubmit: function (event) {
    event.preventDefault();
    console.log('Running');
  },
  render: function () {
    return (
      <form className="noticeForm" onSubmit={this.handleSubmit}>
        <div className="form-group">
          <textarea className="form-control" placeholder="Your notice..." ref="text" />
        </div>
        <input type="submit" className="btn btn-primary" value="Post" />
      </form>
    );
  }
});

var Index = React.createClass({
  render: function () {
    var noticeNodes = this.props.notices.map(function (notice, index) {
      return (
          <Notice key={index} text={notice.text}>
          </Notice>
      );
    });
    return (
        <div>
          <h1>Noticeboard</h1>
          <NoticeForm />
          <div className="noticeList">
            {noticeNodes}
          </div>
        </div>
    );
  }
});

module.exports = Index;

It renders fine on the server side, but I note that the handleSubmit() method of NoticeForm doesn't get bound to the onSubmit event, which seems logical. I'm loading the compiled template file when the page loads, so how can I apply this on page load? It's not clear from the documentation how I do so.

The full source code is here, although I haven't committed the handleSubmit() method yet.


Solution

  • You need to re-render your component on the client side. I think what you are doing right now is just taking what you got from the server and dumping it in with something like

    <div id='view' dangerouslySetInnerHTML={{__html: this.props.body}} /> 
    

    To get the event handlers to actually bind you should do something like

    var container = document.getElementById('view');
    var component = YOURCOMPONENT HERE
    React.renderComponent(component, container);
    

    Taking a look at the API doc this will not actually unmount all the domnodes and redraw. It should only attach all the necessary event handlers

    https://facebook.github.io/react/docs/top-level-api.html

    If you call React.render() on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.