J'essaie de convertir un composant jQuery en React.js et l'une des choses qui me pose problème est le rendu d'un nombre n d'éléments basé sur une boucle for.
Je comprends que ce n'est pas possible, ou recommandé, et que lorsqu'un tableau existe dans le modèle, il est tout à fait logique d'utiliser map
. C'est bien, mais qu'en est-il lorsque vous n'avez pas de tableau ? Au lieu de cela, vous avez une valeur numérique qui équivaut à un nombre donné d'éléments à rendre, alors que devez-vous faire ?
Voici mon exemple : je veux préfixer un élément avec un nombre arbitraire de balises span en fonction de son niveau hiérarchique. Ainsi, au niveau 3, je veux 3 balises span avant l'élément texte.
En javascript :
for (var i = 0; i < level; i++) {
$el.append('<span class="indent"></span>');
}
$el.append('Some text value');
Je n’arrive pas à faire fonctionner cette fonction, ou quelque chose de similaire, dans un composant JSX React.js. Au lieu de cela, j'ai dû faire ce qui suit, en construisant d'abord un tableau temporaire à la bonne longueur, puis en bouclant le tableau.
React.js
render: function() {
var tmp = [];
for (var i = 0; i < this.props.level; i++) {
tmp.push(i);
}
var indents = tmp.map(function (i) {
return (
<span className='indent'></span>
);
});
return (
...
{indents}
"Some text value"
...
);
}
Ce n'est sûrement pas la meilleure, ni la seule façon d'y parvenir ? Qu'est-ce qui m'échappe ?
Mise à jour : A partir de React > 0.16
La méthode Render ne doit pas nécessairement retourner un seul élément. Un tableau peut également être retourné.
var indents = [];
for (var i = 0; i < this.props.level; i++) {
indents.push(<span className='indent' key={i}></span>);
}
return indents;
OU
return this.props.level.map((item, index) => (
<span className="indent" key={index}>
{index}
</span>
));
[Docs ici expliquant les enfants JSX][1]
OLD:
Vous pouvez utiliser une boucle à la place
var indents = [];
for (var i = 0; i < this.props.level; i++) {
indents.push(<span className='indent' key={i}></span>);
}
return (
<div>
{indents}
"Some text value"
</div>
);
Vous pouvez aussi utiliser [.map][2] et fancy es6
return (
<div>
{this.props.level.map((item, index) => (
<span className='indent' key={index} />
))}
"Some text value"
</div>
);
De plus, vous devez envelopper la valeur de retour dans un conteneur. J'ai utilisé div dans l'exemple ci-dessus
Comme le dit la documentation [ici][3]
Actuellement, dans le rendu d'un composant, vous ne pouvez renvoyer qu'un seul nœud ; si vous avez, par exemple, une liste de div à renvoyer, vous devez envelopper vos composants dans un div, un span ou tout autre composant.
[1] : https://reactjs.org/docs/jsx-in-depth.html#jsx-children [2] : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map [3] : http://facebook.github.io/react/tips/maximum-number-of-jsx-root-nodes.html
Voici un exemple plus fonctionnel avec quelques fonctionnalités ES6 :
'use strict';
const React = require('react');
function renderArticles(articles) {
if (articles.length > 0) {
return articles.map((article, index) => (
<Article key={index} article={article} />
));
}
else return [];
}
const Article = ({article}) => {
return (
<article key={article.id}>
<a href={article.link}>{article.title}</a>
<p>{article.description}</p>
</article>
);
};
const Articles = React.createClass({
render() {
const articles = renderArticles(this.props.articles);
return (
<section>
{ articles }
</section>
);
}
});
module.exports = Articles;
J'utilise Object.keys(chars).map(...)
pour boucler dans le rendu
// chars = {a:true, b:false, ..., z:false}
render() {
return (
<div>
{chars && Object.keys(chars).map(function(char, idx) {
return <span key={idx}>{char}</span>;
}.bind(this))}
"Some text value"
</div>
);
}