Notes

React

01 May 2014

Update: The world has moved on, typically you’ll want to use browserify or webpack, I have updated the example repository to work via npm rather than with a lib directory and with a much newer version of react.

I’ve been experimenting with Facebook’s React framework. I spent a little time working out how to use it with require.js and so thought I’d write a little on how that went. I was interested in getting require.js to work rather than browserify (reactify) as I like being able to have a development environment where the browser’s just grabbing the sources, compiling the jsx on the fly.

What I did initially was create a copy of the React tutorial where I split each component into its own file - to simulate how the UI for a real App would be split among modules. The commit with the intial state can be found here. This way I’ve built an example of the minimum needed to tie these two technologies. For those who learn better from just being able to investigate a small codebase the source code is here.

I got this going using the jsx-requirejs-plugin.

The first step was that I moved over to using local copies of the various dependencies in a lib directory. jsx-requirejs-plugin needs its own updated version of JSXTransformer, the text.js library, its own file and the require.js dependencies.

So the lib directory looks like…

The index.html ends up being very trivial now, just loading a single “main” script:

<!DOCTYPE html>
<html>
  <head>
    <title>Hello React</title>
    <script data-main="main" src="lib/require.js"></script>
  </head>
  <body>
    <div id="content"></div>
  </body>
</html>

The main script itself loads the CommentBox and renders it into the page:

The first part of main.js configures requirejs, giving us short labels for each of the third-party dependencies.

require.config({
  paths: {
    text: "lib/text",
    jsx: "lib/jsx",
    showdown: "lib/showdown",
    react: "lib/react-0.10.0",
    JSXTransformer: "lib/JSXTransformer-0.10.0",
  },
});

The second part of main.js actuall does the work, it states its dependency of react and the comment box component and then uses react to render the component. Note that we’re rendering the component in the JavaScript form, not using JSX.

Notice how the files with JSX code are prefixed with a jsx! to identify them for pre-processing.

require(["react", "jsx!comment-box"], function (React, CommentBox) {
  var data = [
    { author: "Pete Hunt", text: "This is one comment" },
    { author: "Jordan Walke", text: "This is *another* comment" },
  ];
  React.renderComponent(
    new CommentBox({ data: data }),
    document.getElementById("content")
  );
});

I’ll just include one example of a component, the form is the same for the other components. I had to rename the jsx files to js for requirejs to find them (though this can be fixed via config).

/**
 * @jsx React.DOM
 */
define(["react", "jsx!comment-list", "jsx!comment-form"], function (
  React,
  CommentList,
  CommentForm
) {
  var CommentBox = React.createClass({
    getInitialState: function () {
      return { data: this.props.data };
    },
    handleCommentSubmit: function (comment) {
      var comments = this.state.data;
      var newComments = comments.concat([comment]);
      this.setState({ data: newComments });
    },
    render: function () {
      return (
        <div className="commentBox">
          <h1>Comments</h1>
          <CommentList data={this.state.data} />
          <CommentForm onCommentSubmit={this.handleCommentSubmit} />
        </div>
      );
    },
  });
  return CommentBox;
});