web-dev-qa-db-ja.com

ReactJS:子コンポーネントに配置されたときにonClickハンドラーが起動しない

私は最近ReactJSの使用を開始しました。具体的には、react-Rails Ruby gemおよびreact-bootstrapコンポーネントを利用しています。

onClickイベントリスナーを子コンポーネントに配置することに関して質問があります。

以下のコードサンプルからわかるように、render関数で子コンポーネントを「呼び出す」親コンポーネントがあります。そのrender関数内には、クリックされたときにonClickを呼び出すReact handleToggleリスナーがあります。

###* @jsx React.DOM ###

ToggleIconButton = React.createClass
  getInitialState: ->
    toggleOn: false
  handleToggle: (evt) ->
    this.setState(toggleOn: !this.state.toggleOn)
  render: ->
    `<IconButton onClick={this.handleToggle}>Toggle Button</IconButton>`

IconButton = React.createClass
  render: ->
    # BsButton and BsGlyphicon are React-Bootstrap components
    `<BsButton>
      <BsGlyphicon glyph={this.props.glyph} />
      {" " + this.props.text}
     </BsButton>`

残念ながら、これは思ったようには機能しません。 ToggleIconButton::handleToggleは呼び出されません。代わりに、onClickリスナーがIconButtonに配置され、ToggleIconButton::handleToggleを参照します。

React Dev Tool Screen


IconButtonに追加の動作を追加したくありません。私の考えでは、IconButtonに条件付きロジックを配置する必要はありません。すべきことは、アイコンとボタンを表すことだけで、ブラウザイベントを心配する必要はありません。それがToggleIconButtonの目的です。

React DivIconButtonで囲み、そこにonClickリスナーを書くことができることは知っていますが(これを試してみましたが、動作します)、それは少しジャンキーなようです。

誰かがこれを行う良い方法を知っていますか?みんなありがとう!

55
Kurt Mueller

したがって、この場合のイベント処理の適切な方法は、イベントハンドラーを子コンポーネントに渡すことです。あなたが望むものを達成するいくつかの方法があり、この動作を異なる方法で実装するかもしれません(ユースケースがわからない)が、親コンポーネントと子コンポーネント間の典型的なイベント処理を示すJSXの例を用意しました。ここで見つけることができます...

JSフィドル

次のように考えてください:

var ParentComponent = React.createClass({
    render: function(){
        return (
            <ChildComponent onSomeEvent={this.handleThatEvent} />;
        )
    },
    handleThatEvent: function(e){
         //update state, etc.
    }
});

var ChildComponent = React.createClass({
    render: function(){
        return (
           <input type="button" onClick={this.props.onSomeEvent} value="Click Me!" />
        )
    }
});
80
captray

ノードを呼び出す前に、レンダーのthisを参照するvarを作成する場合、子コンポーネントを作成する必要はありません。

var self = this;

そのため、たとえば(これは考案されており、この場合var selfは必要ありませんが、ネストされたreturnステートメントの場合は必要になります)。

var ParentComponent = React.createClass({
    render: function(){
        var self = this;
        return (
            <input type="button" onClick={self.handleThatEvent} value="Click Me!" />;
        )
    },
    handleThatEvent: function(e){
         //update state, etc.
    }
});

さらに良いことに、これを関数にバインドできます。

var ParentComponent = React.createClass({
    render: function(){
        return (
            this.state.array.map(function(){
              return (<input type="button" onClick={this.handleThatEvent} value="Click Me!" />);
            }.bind(this));
        )
    },
    handleThatEvent: function(e){
         //update state, etc.
    }
});

または、コメントでcaptrayの提案に従う

var ParentComponent = React.createClass({
    render: function(){
        return (
            this.state.array.map(function(){
              return (<input type="button" onClick={this.handleThatEvent} value="Click Me!" />);
            }, this);
        )
    },
    handleThatEvent: function(e){
         //update state, etc.
    }
});
9
vipero07