関連するReactコンポーネント間で通信するにはどうすればよいですか? 質問する

関連するReactコンポーネント間で通信するにはどうすればよいですか? 質問する

私は ReactJS を使い始めたばかりですが、問題に少し困っています。

私のアプリケーションは、基本的にフィルターとレイアウトを変更するボタンが付いたリストです。現時点では、、の 3 つのコンポーネントを使用していますが、<list />当然ながら、 で設定を変更したときに、 の何らかのメソッドをトリガーしてビューを更新したいと考えています。< Filters /><TopBar />< Filters /><list />

これら 3 つのコンポーネントを相互にやり取りさせるにはどうすればよいのでしょうか。それとも、変更を加えることができる何らかのグローバル データ モデルが必要ですか。

ベストアンサー1

最適なアプローチは、これらのコンポーネントをどのように配置するかによって異なります。今思い浮かぶシナリオの例をいくつか挙げます。

  1. <Filters />の子コンポーネントです<List />
  2. <Filters />と は両方とも<List />親コンポーネントの子です
  3. <Filters /><List />完全に別のルート コンポーネントに存在します。

私が考えていないシナリオが他にもあるかもしれません。あなたのシナリオがこれらに当てはまらない場合は、私に知らせてください。最初の 2 つのシナリオに私がどのように対処してきたか、大まかな例をいくつか示します。

シナリオ#1

<List />からにハンドラーを渡し<Filters />、イベントで呼び出してonChange現在の値でリストをフィルターすることができます。

#1 の JSFiddle →

/** @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 />

#2 の JSFiddle →

/** @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

コンポーネントが親子関係で通信できない場合、ドキュメントではグローバルイベントシステムの設定を推奨しています

おすすめ記事