web-dev-qa-db-fra.com

ReactJS: le gestionnaire onClick ne se déclenche pas lorsqu'il est placé sur un composant enfant

J'ai récemment commencé à travailler avec ReactJS. Plus précisément, j'utilise le react-Rails Ruby gem et react-bootstrap Composants.

J'ai une question concernant le placement de onClick auditeurs d'événement dans des composants enfants.

Comme vous pouvez le constater dans l'exemple de code ci-dessous, j'ai un composant parent qui "appelle" un composant enfant dans sa fonction render. Dans cette fonction render, j'ai React onClick écouteur qui appelle handleToggle lorsque l'on clique dessus.).

###* @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>`

Malheureusement, cela ne fonctionne pas comme je le pensais. ToggleIconButton::handleToggle ne se fait jamais appeler. Au lieu de cela, le onClick écouteur est placé sur IconButton et fait référence à ToggleIconButton::handleToggle.

React Dev Tool Screen


Je ne veux pas ajouter de comportement supplémentaire à IconButton. À mon avis, aucune logique conditionnelle ne devrait être placée dans IconButton. Tout ce qu'il devrait faire est de représenter une icône et un bouton et ne pas avoir à s'inquiéter des événements du navigateur. C'est ce à quoi ToggleIconButton est destiné.

Bien que je sache, je pourrais envelopper un React Div autour de IconButton et écrire un auditeur onClick (je l'ai essayé et cela fonctionne), il semblerait que ce soit un peu janky.

Est-ce que quelqu'un connaît un bon moyen de faire cela? Merci les gars!

55
Kurt Mueller

Dans ce cas, la meilleure façon de gérer les événements est de transmettre le gestionnaire d'événements au composant enfant. Il y a plusieurs façons d'accomplir ce que vous voulez, et je pourrais implémenter ce problème différemment (je ne suis pas sûr du cas d'utilisation), mais j'ai câblé un exemple dans JSX pour vous qui illustre la gestion des événements typiques entre les composants parent et enfant. Vous pouvez le trouver ici...

JS Fiddle

Pensez-y comme ceci:

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

Vous n'avez pas besoin de créer un composant enfant si, avant d'appeler le nœud, vous créez une variable pour référencer le rendu, c'est-à-dire.

var self = this;

Ainsi, par exemple (ceci est artificiel et le var self n'est pas nécessaire dans ce cas, mais dans le cas d'instructions de retour imbriquées, il serait requis).

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.
    }
});

Mieux encore, vous pouvez lier ceci à la fonction.

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.
    }
});

Ou suivre la suggestion de Captray dans les commentaires

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