どうも、イソップです。
Reactアプリケーションでは、データをループ処理で一覧表示することが多いと思います。
その際によくあるのは、少しだけ違うコンポーネントが複数ある場合にループ用コンポーネントをたくさん作ってしまうこと。
例えば、参照するデータは同じだけど、表示するコンポーネントの見ためがほんの少しだけ違うとか。
そういうケースが増えると、非常に管理が煩雑になりがちです。
そこで、今回はループ用の親コンポーネントを用意して、
その中のデータ表示用コンポーネントを親コンポーネントから指定できる方法を紹介します。
コンポーネントを用意
次のようなデータがあります。
const data = [ 'foo', 'bar', 'baz' ];
この表示用コンポーネントを用意します。
データを表示するだけの子コンポーネント
class ListItem extends Component {
render() {
return(
<li>{this.props.text}</li>
);
}
}
アイコン付きの子コンポーネント
class IconListItem extends Component {
render() {
return(
<li>
<i className="icon"></i>
<span>{this.props.text}</span>
</li>
);
}
}
リスト表示するための親コンポーネント
import React, { Component } from 'react';
import ListItem from './ListItem';
class List extends Component {
render() {
const { data, component } = this.props;
let ChildComponent = component || ListItem;
return(
<ul>
{data.map((text, i) => {
return React.createElement(ChildComponent, { key: i, text });
})}
</ul>
);
}
}
React.createElement() の部分が特に重要です。
React.createElement()
createElement はReactのコンポーネントを作成するAPIで、React.Componentを介さず自分でReactコンポーネントを作成することができます。
React.createElement(
type,
[props],
[...children]
)
typeにはコンポーネント名か、クラスもしくは関数を渡すことができます。propsはプロパティをオブジェクトで渡します。childrenはそのまま、コンポーネントのタグの中(<Hoge>...</Hoge>)のコンテンツが渡ります。
React Top-Level API #createElement
親に子コンポーネントを渡してあげる
createElement でコンポーネントを動的生成できるようにした List コンポーネントは、次のように使います。
const data = [ 'foo', 'bar', 'baz' ];
...
<List data={data} component={IconListItem} />
component プロパティに子コンポーネントを指定できるようにして、
List コンポーネントの種類違いを作らないようにしています。
component に何も指定しなければ、ListItem が使われます。
Listコンポーネント
const { data, component } = this.props;
let ChildComponent = component || ListItem;
React.createElement メソッドを活用することで、クリーンな設計にすることができます。
