1. ホーム
  2. ジャバスクリプト

[解決済み】ReactJS 2つのコンポーネントが通信しています。

2022-03-25 03:55:40

質問

ReactJSを始めたばかりですが、ある問題で少し行き詰っています。

私のアプリケーションは、基本的にフィルタとレイアウトを変更するためのボタンを持つリストです。 今のところ、3つのコンポーネントを使用しています。 <list /> , < Filters /><TopBar /> での設定を変更すると、明らかに < Filters /> で何らかのメソッドを起動させたい。 <list /> を使用してビューを更新します。

この3つのコンポーネントが相互に作用するようにするにはどうすればよいでしょうか。それとも、ある種のグローバルなデータモデルが必要で、そこに変更を加えるだけでよいのでしょうか。

どのように解決するのですか?

最適な方法は、これらのコンポーネントをどのように配置するかによります。今すぐ思いつくシナリオの例をいくつか挙げてみましょう。

  1. <Filters /> の子コンポーネントです。 <List />
  2. 両方 <Filters /><List /> は、親コンポーネントの子コンポーネント
  3. <Filters /><List /> は完全に別のルートコンポーネントに住んでいます。

私が考えていない他のシナリオもあるかもしれません。もし、あなたのものがこれらのシナリオに当てはまらないのであれば、私に教えてください。以下は、私が最初の2つのシナリオをどのように扱っているかの、非常に大まかな例です。

シナリオ#1

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

JSFiddle for #1 →

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

JSFiddle for #2 →

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

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