web-dev-qa-db-fra.com

Comment définir le gestionnaire d'événements dans le sous-composant React

Je ne parviens pas à connecter des éléments de menu à un gestionnaire d'événements. Voici une maquette de l'interface utilisateur montrant les changements d'état au fil du temps. C'est un menu déroulant (via Bootstrap), avec l'élément de menu racine montrant la sélection en cours:

[ANN]<click  ...  [ANN]             ...    [BOB]<click  ...  [BOB]  
                    [Ann]                                      [Ann]
                    [Bob]<click + ajax                         [Bob]
                    [Cal]                                      [Cal]

L'objectif final est de modifier le contenu de la page de manière asynchrone en fonction de la sélection de l'utilisateur. Un clic sur Bob devrait déclencher la variable handleClick, mais ce n’est pas le cas.

En passant, je ne suis pas très heureux de la façon dont composantDidMount appelle this.handleClick();, mais cela fonctionne pour le moment comme moyen d'obtenir le contenu du menu initial du serveur.

/** @jsx React.DOM */

var CurrentSelection = React.createClass({
  componentDidMount: function() {
    this.handleClick();
  },

  handleClick: function(event) {
    alert('clicked');
    // Ajax details ommitted since we never get here via onClick
  },
  getInitialState: function() {
    return {title: "Loading items...", items: []};
  },
  render: function() {
    var itemNodes = this.state.items.map(function (item) {
      return <li key={item}><a href='#' onClick={this.handleClick}>{item}</a></li>;
    });

    return <ul className='nav'>
      <li className='dropdown'>
        <a href='#' className='dropdown-toggle' data-toggle='dropdown'>{this.state.title}</a>
        <ul className='dropdown-menu'>{itemNodes}</ul>
      </li>
    </ul>;
  }
});


$(document).ready(function() {
  React.renderComponent(
    CurrentSelection(),
    document.getElementById('item-selection')
  );
});

Je suis presque certain que ma floue compréhension de la portée de javascript est à blâmer, mais tout ce que j'ai essayé jusqu'à présent a échoué (y compris essayer de transmettre le gestionnaire à l'aide d'accessoires).

21
clozach

Le problème est que vous créez les nœuds d'élément à l'aide d'une fonction anonyme, et que this signifie window. Le correctif consiste à ajouter .bind(this) à la fonction anonyme.

var itemNodes = this.state.items.map(function (item) {
  return <li key={item}><a href='#' onClick={this.handleClick}>{item}</a></li>;
}.bind(this));

Ou créez une copie de this et utilisez-la à la place:

var _this = this, itemNodes = this.state.items.map(function (item) {
  return <li key={item}><a href='#' onClick={_this.handleClick}>{item}</a></li>;
})
40
tungd

Comme je peux comprendre les spécifications de la tâche pour "Anna", "Bob", "Cal", la solution peut être la suivante (basée sur un composant de réaction et ES6):

La démo de base en direct est ici

import React, { Component } from "react"

export default class CurrentSelection extends Component {
  constructor() {
    super()
    this.state = {
      index: 0
    }
    this.list = ["Anna", "Bob", "Cal"]
  }

  listLi = list => {
    return list.map((item, index) => (
      <li key={index}>
        <a
          name={item}
          href="#"
          onClick={e => this.onEvent(e, index)}
        >
          {item}
        </a>
      </li>
    ))
  }

  onEvent = (e, index) => {
    console.info("CurrentSelection->onEvent()", { [e.target.name]: index })
    this.setState({ index })
  }

  getCurrentSelection = () => {
    const { index } = this.state
    return this.list[index]
  }

  render() {
    return (
      <div>
        <ul>{this.listLi(this.list)}</ul>
        <div>{this.getCurrentSelection()}</div>
      </div>
    )
  }
}
0
Roman