Sto cercando di convertire un componente jQuery in React.js e una delle cose con cui ho difficoltà è il rendering di un numero n di elementi basato su un ciclo for.
Ho capito che questo non è possibile, o raccomandato e che dove esiste un array nel modello ha completamente senso usare map
. Questo va bene, ma cosa succede quando non si ha un array? Invece si ha un valore numerico che equivale ad un dato numero di elementi da rendere, allora cosa si dovrebbe fare?
Ecco il mio esempio, voglio prefissare un elemento con un numero arbitrario di tag span basato sul suo livello gerarchico. Così al livello 3, voglio 3 tag span prima dell'elemento testo.
In javascript:
for (var i = 0; i < level; i++) {
$el.append('<span class="indent"></span>');
}
$el.append('Some text value');
Non riesco a far funzionare questo, o qualcosa di simile, in un componente JSX React.js. Invece ho dovuto fare quanto segue, costruendo prima un array temporaneo alla lunghezza corretta e poi eseguendo il looping dell'array.
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"
...
);
}
Sicuramente questo non può essere il migliore, o l'unico modo per ottenere questo? Cosa mi manca?
Aggiornato: A partire da React > 0.16
Il metodo Render non deve necessariamente restituire un singolo elemento. Si può anche restituire un array.
var indents = [];
for (var i = 0; i < this.props.level; i++) {
indents.push(<span className='indent' key={i}></span>);
}
return indents;
O
return this.props.level.map((item, index) => (
<span className="indent" key={index}>
{index}
</span>
));
Docs qui che spiegano i bambini JSX
OLD:
Potete invece usare un ciclo
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>
);
Puoi anche usare .map e la fantasia es6
return (
<div>
{this.props.level.map((item, index) => (
<span className='indent' key={index} />
))}
"Some text value"
</div>
);
Inoltre, devi avvolgere il valore di ritorno in un contenitore. Ho usato div nell'esempio precedente
Come dicono i documenti qui
Attualmente, nel render di un componente, puoi restituire solo un nodo; se hai, per esempio, una lista di div da restituire, devi avvolgere i tuoi componenti all'interno di un div, span o qualsiasi altro componente.
Ecco un esempio più funzionale con alcune caratteristiche 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;
Sto usando Object.keys(chars).map(...)
per fare un loop nel render
// 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>
);
}