web-dev-qa-db-fra.com

React.js: comment découpler jsx de JavaScript

Existe-t-il un moyen de déplacer le jsx de la fonction de rendu d'un composant vers un fichier séparé? Si oui, comment référencer le jsx dans la fonction de rendu?

58
tldr

Voici un modèle pour séparer le modèle jsx qui utilise les modules CommonJS dans NodeJS, Browserify ou Webpack. Dans NodeJS, j'ai trouvé le module node-jsx utile pour éviter d'avoir à compiler le 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>
  );

};

Mise à jour 2015-1-30: suggestion intégrée dans la réponse de Damon Smith pour définir this dans la fonction de modèle sur le composant React.

Mise à jour 12/2016: la meilleure pratique actuelle consiste à utiliser l'extension .js et à utiliser un outil de construction comme Babel pour sortir le javascript final à partir de votre source. Jetez un œil à create-react-app si vous ne faites que commencer. En outre, les dernières meilleures pratiques React recommandent une séparation entre les composants qui gèrent l'état (généralement appelés "composants de conteneur") et les composants de présentation. Ces composants de présentation peuvent désormais être écrits en tant que fonctions, donc ils ne sont pas loin de la fonction de modèle utilisée dans l'exemple précédent. Voici comment je recommanderais de découpler la plupart du code JSX de présentation maintenant. Ces exemples utilisent toujours la syntaxe ES5 React.createClass() =.

// 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>
  );
};
20
rmarscher

Vous pouvez utiliser react-templates . Il vous donne exactement cette séparation entre le balisage et le composant lui-même, et bien plus encore.

Je l'ai trouvé très utile pour mes besoins (une application web à grande échelle).

28
tomericco

Un problème avec le déplacement de modèles dans un fichier séparé est que si vous utilisez des gestionnaires comme:

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

puis dans votre composant, vous utilisez:

render: function() {
    return myTemplate;
}

le code du modèle généré appellera this.handleSubmit (), donc "this" sera faux et les gestionnaires ne fonctionneront pas. Ce que vous devez faire, c'est les mettre dans une fonction, comme ceci:

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

puis dans la fonction de rendu de votre composant, vous devez le lier correctement à "ceci", puis l'appeler comme ceci:

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

Vous pouvez maintenant mettre cette définition de modèle n'importe où, dans un fichier séparé ou comme vous le souhaitez pour structurer et référencer votre propre code. (pouvoir pour vous! N'écoutez pas ces cadres normatifs fous! :))

23
Damon Smith

Je viens de séparer JSX en fichiers de fonctions anonymes

template.js

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

mon-composant.js

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

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

Dans le modèle, vous pouvez accéder aux accessoires ou à l'état ou aux fonctions à l'aide de la variable component.

12
Ivan Bajalovic

Si vous n'utilisez aucun système de modules, c'est-à-dire que vous ne comptez que sur les balises script, exposez simplement votre composant JSX dans une variable globale et utilisez-le lorsque vous en avez besoin:

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

Remarque: la balise script pour component.js doit apparaître avant la balise script pour main.js.

Si vous utilisez un système de modules de type Commonjs comme Browserify, exportez simplement votre définition de composant et exigez-la lorsque vous en avez besoin.

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