React.js: how to decouple jsx out of JavaScript

99封情书 提交于 2020-08-20 16:56:29

问题


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?


回答1:


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>
  );
};



回答2:


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).




回答3:


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! :) )




回答4:


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.




回答5:


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);


来源:https://stackoverflow.com/questions/21066581/react-js-how-to-decouple-jsx-out-of-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!