私は ReactJS を使い始めたばかりですが、問題に少し困っています。
私のアプリケーションは、基本的にフィルターとレイアウトを変更するボタンが付いたリストです。現時点では、、の 3 つのコンポーネントを使用していますが、<list />
当然ながら、 で設定を変更したときに、 の何らかのメソッドをトリガーしてビューを更新したいと考えています。< Filters />
<TopBar />
< Filters />
<list />
これら 3 つのコンポーネントを相互にやり取りさせるにはどうすればよいのでしょうか。それとも、変更を加えることができる何らかのグローバル データ モデルが必要ですか。
ベストアンサー1
最適なアプローチは、これらのコンポーネントをどのように配置するかによって異なります。今思い浮かぶシナリオの例をいくつか挙げます。
<Filters />
の子コンポーネントです<List />
<Filters />
と は両方とも<List />
親コンポーネントの子です<Filters />
<List />
完全に別のルート コンポーネントに存在します。
私が考えていないシナリオが他にもあるかもしれません。あなたのシナリオがこれらに当てはまらない場合は、私に知らせてください。最初の 2 つのシナリオに私がどのように対処してきたか、大まかな例をいくつか示します。
シナリオ#1
<List />
からにハンドラーを渡し<Filters />
、イベントで呼び出してonChange
現在の値でリストをフィルターすることができます。
/** @jsx React.DOM */
var Filters = React.createClass({
handleFilterChange: function() {
var value = this.refs.filterInput.getDOMNode().value;
this.props.updateFilter(value);
},
render: function() {
return <input type="text" ref="filterInput" onChange={this.handleFilterChange} placeholder="Filter" />;
}
});
var List = React.createClass({
getInitialState: function() {
return {
listItems: ['Chicago', 'New York', 'Tokyo', 'London', 'San Francisco', 'Amsterdam', 'Hong Kong'],
nameFilter: ''
};
},
handleFilterUpdate: function(filterValue) {
this.setState({
nameFilter: filterValue
});
},
render: function() {
var displayedItems = this.state.listItems.filter(function(item) {
var match = item.toLowerCase().indexOf(this.state.nameFilter.toLowerCase());
return (match !== -1);
}.bind(this));
var content;
if (displayedItems.length > 0) {
var items = displayedItems.map(function(item) {
return <li>{item}</li>;
});
content = <ul>{items}</ul>
} else {
content = <p>No items matching this filter</p>;
}
return (
<div>
<Filters updateFilter={this.handleFilterUpdate} />
<h4>Results</h4>
{content}
</div>
);
}
});
React.renderComponent(<List />, document.body);
シナリオ #2
シナリオ 1 と似ていますが、親コンポーネントがハンドラー関数を に渡し<Filters />
、フィルタリングされたリストを に渡します。を から<List />
切り離すので、この方法の方が気に入っています。<List />
<Filters />
/** @jsx React.DOM */
var Filters = React.createClass({
handleFilterChange: function() {
var value = this.refs.filterInput.getDOMNode().value;
this.props.updateFilter(value);
},
render: function() {
return <input type="text" ref="filterInput" onChange={this.handleFilterChange} placeholder="Filter" />;
}
});
var List = React.createClass({
render: function() {
var content;
if (this.props.items.length > 0) {
var items = this.props.items.map(function(item) {
return <li>{item}</li>;
});
content = <ul>{items}</ul>
} else {
content = <p>No items matching this filter</p>;
}
return (
<div className="results">
<h4>Results</h4>
{content}
</div>
);
}
});
var ListContainer = React.createClass({
getInitialState: function() {
return {
listItems: ['Chicago', 'New York', 'Tokyo', 'London', 'San Francisco', 'Amsterdam', 'Hong Kong'],
nameFilter: ''
};
},
handleFilterUpdate: function(filterValue) {
this.setState({
nameFilter: filterValue
});
},
render: function() {
var displayedItems = this.state.listItems.filter(function(item) {
var match = item.toLowerCase().indexOf(this.state.nameFilter.toLowerCase());
return (match !== -1);
}.bind(this));
return (
<div>
<Filters updateFilter={this.handleFilterUpdate} />
<List items={displayedItems} />
</div>
);
}
});
React.renderComponent(<ListContainer />, document.body);
シナリオ #3
コンポーネントが親子関係で通信できない場合、ドキュメントではグローバルイベントシステムの設定を推奨しています。