React.js: how to decouple jsx out of JavaScript

JavascriptReactjsReact Jsx

Javascript Problem Overview


Is there any way to move the jsx from a component's render function to a separate file? If so, how do I reference the jsx in the render function?

Javascript Solutions


Solution 1 - Javascript

You can use react-templates. It gives you exactly this separation between the markup and the component itself, and much more.

I found it very useful for my needs (a large scale web app).

Solution 2 - Javascript

One problem with moving templates into a separate file is that if you use handlers like:

var myTemplate = (
    <form onSubmit={this.handleSubmit}></form>
);

and then in your component you use:

render: function() {
    return myTemplate;
}

the generated template code will call this.handleSubmit(), so the "this" will be wrong and the handlers won't work. What you need to do is put them in a function, like this:

var myTemplate = function() {
	return (
		<form onSubmit={this.handleSubmit}></form>
	);
};

then in your component's render function, you need to bind it to 'this' correctly, then call it, like this:

render: function() {
	return myTemplate.bind(this)();
},

Now you can put that template definition anywhere, in a separate file or however you want to structure and reference your own code. (power to you! Don't listen to these crazy prescriptive frameworks! :) )

Solution 3 - Javascript

Here is a pattern for separating the template jsx that uses CommonJS modules in NodeJS, Browserify or Webpack. In NodeJS, I found the node-jsx module helpful to avoid the need to compile the JSX.

// index.js
require('node-jsx').install({extension: '.jsx'});
var React = require('react'),
    Component = require('./your-component');


// your-component.jsx
var YourComponent,
    React = require('react'),
    template = require('./templates/your-component.jsx');

module.exports = YourComponent = React.createClass({
  render: function() {
    return template.call(this);
  }
});


// templates/your-component.jsx
/** @jsx React.DOM */
var React = require('react');

module.exports = function() {

  return (
    <div>
      Your template content.
    </div>
  );

};

Update 2015-1-30: incorporated suggestion in Damon Smith's answer to set this in the template function to the React component.

Update 12/2016: the current best practice is to use the .js extension and use a build tool like Babel to output the final javascript from your source. Take a look at create-react-app if you're just getting started. Also, the latest React best practices do recommend a separation between components that manage state (typically called "container components") and components that are presentational. These presentational components can now be written as functions, so they are not far off from the template function used in the previous example. Here is how I would recommend decoupling most of the presentational JSX code now. These examples still use the ES5 React.createClass() syntax.

// index.js
var React = require('react'),
    ReactDOM = require('react-dom'),
    YourComponent = require('./your-component');

ReactDOM.render(
  React.createElement(YourComponent, {}, null),
  document.getElementById('root')
);

// your-component.js
var React = require('react'),
    YourComponentTemplate = require('./templates/your-component');

var YourComponentContainer = React.createClass({
  getInitialState: function() {
    return {
      color: 'green'
    };
  },

  toggleColor: function() {
    this.setState({
      color: this.state.color === 'green' ? 'blue' : 'green'
    });
  },

  render: function() {
    var componentProps = {
      color: this.state.color,
      onClick: this.toggleColor
    };
    return <YourComponentTemplate {...componentProps} />;
  }
});

module.exports = YourComponentContainer;

// templates/your-component.js
var React = require('react');

module.exports = function YourComponentTemplate(props) {
  return (
    <div style={{color: props.color}} onClick={props.onClick}>
      Your template content.
    </div>
  );
};

Solution 4 - Javascript

I just separated JSX into anonymous function files

template.js

export default (component) => {
return <h1>Hello {component.props.name}</h1>
}

my-component.js

import React, {Component} from 'react';
import template from './template';

export default MyComponent extends Component {
   render() {
     return template(this);
   }
}

In template you can access props or state or functions using component variable.

Solution 5 - Javascript

If you don't use any module system, i.e. rely on script tags only, simple expose your JSX component in a global variable and use it when you need :

// component.js
var Component = React.createClass({ /* your component */ });
// main.js
React.renderComponent(Component({}), domNode);

Note : the script tag for component.js must appear before the script tag for main.js.

If you use a Commonjs-like module system like Browserify, simply export your component definition and require it when you need it.

// component.js
var React = require("react");
module.exports = React.createClass({ /* your component */ });
// main.js
var Component = require("component.js");
React.renderComponent(Component({}), domNode);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontldrView Question on Stackoverflow
Solution 1 - JavascripttomericcoView Answer on Stackoverflow
Solution 2 - JavascriptDamon SmithView Answer on Stackoverflow
Solution 3 - JavascriptrmarscherView Answer on Stackoverflow
Solution 4 - JavascriptIvan BajalovicView Answer on Stackoverflow
Solution 5 - JavascriptDjebbZView Answer on Stackoverflow