web-dev-qa-db-de.com

Festlegen des Ereignishandlers in der Unterkomponente "React"

Ich habe Probleme, Menüelemente mit einem Ereignishandler zu verbinden. Hier ist ein Mock der Benutzeroberfläche, der Statusänderungen im Laufe der Zeit zeigt. Es ist ein Dropdown-Menü (über Bootstrap), wobei der Hauptmenüpunkt die aktuelle Auswahl anzeigt:

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

Das Endziel besteht darin, den Seiteninhalt asynchron basierend auf der Auswahl des Benutzers zu ändern. Ein Klick auf Bob sollte die handleClick auslösen, ist es aber nicht.

Als Randbemerkung bin ich mit der Art und Weise, wie ComponentDidMount this.handleClick(); aufruft, nicht besonders glücklich, aber es funktioniert vorerst als eine Möglichkeit, erste Menüinhalte vom Server abzurufen.

/** @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')
  );
});

Ich bin fast sicher, dass mein dunstiges Verständnis von Javascript-Scoping Schuld ist, aber alles, was ich bisher ausprobiert habe, ist fehlgeschlagen (einschließlich des Versuches, den Handler durch Requisiten zu übergeben).

21
clozach

Das Problem ist, dass Sie die Elementknoten mit einer anonymen Funktion erstellen und this die window bedeutet. Das Update besteht darin, .bind(this) zur anonymen Funktion hinzuzufügen.

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

Oder erstellen Sie eine Kopie von this und verwenden Sie stattdessen Folgendes:

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

Da ich die Spezifikation der Aufgabe für "Anna", "Bob", "Cal" verstehen kann, kann die Lösung die folgende sein (basierend auf einer Reaktionskomponente und ES6):

Grundlegende Live-Demo ist da

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