jQueryのコンポーネントをReact.jsに変換しようとしているのですが、その中で困っているのが、forループに基づいてn個の要素をレンダリングすることです。
モデルに配列が存在する場合、map
を使用するのが完全に理にかなっていることは理解しています。 しかし、配列が存在しない場合はどうでしょうか。 その代わりに、レンダリングする要素の数に相当する数値がある場合はどうすればいいのでしょうか?
ここでは、ある要素に、その階層に応じた任意の数のspanタグを前置したいとします。 例えば、レベル3の場合、text要素の前に3つのspanタグを付けたいとします。
javascriptでは
for (var i = 0; i < level; i++) {
$el.append('<span class="indent"></span>');
}
$el.append('Some text value');
JSXのReact.jsコンポーネントで、これと似たようなものを動作させることができないようです。 代わりに以下のように、まず一時的な配列を正しい長さに構築し、その配列をループさせる必要がありました。
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"
...
);
}
これがベスト、もしくは唯一の方法ではないのでしょうか? 何が足りないのでしょうか?
更新されました。React > 0.16の時点で
Renderメソッドは、必ずしも単一の要素を返す必要はありません。配列を返すことも可能です。
var indents = [];
for (var i = 0; i < this.props.level; i++) {
indents.push(<span className='indent' key={i}></span>);
}
return indents;
または
return this.props.level.map((item, index) => (
<span className="indent" key={index}>
{index}
</span>
));
JSXのchildrenについて説明しているドキュメントがあります。
**古い
代わりに1つのループを使うことができます
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>
);
また、.mapとfancy es6を使用することもできます。
return (
<div>
{this.props.level.map((item, index) => (
<span className='indent' key={index} />
))}
"Some text value"
</div>
);
また、戻り値をコンテナで包む必要があります。上の例ではdivを使いました
ドキュメントによると ここのように
現在、コンポーネントのレンダリングでは、1つのノードしか返すことができません。例えば、返すべきdivのリストがある場合は、コンポーネントをdivやspanなどのコンポーネントで包む必要があります。
ここでは、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;
私は、Object.keys(chars).map(...)
を使って、レンダリングのループをしています。
// 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>
);
}