React.js: how to decouple jsx out of JavaScript

前端 未结 5 1149
你的背包
你的背包 2021-01-30 00:08

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?

相关标签:
5条回答
  • 2021-01-30 00:25

    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.

    0 讨论(0)
  • 2021-01-30 00:31

    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);
    
    0 讨论(0)
  • 2021-01-30 00:35

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

    0 讨论(0)
  • 2021-01-30 00:36

    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>
      );
    };
    
    0 讨论(0)
  • 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! :) )

    0 讨论(0)
提交回复
热议问题