【问题标题】:How to set event handler in React sub-component如何在 React 子组件中设置事件处理程序
【发布时间】:2014-01-27 10:10:48
【问题描述】:

我无法将菜单项连接到事件处理程序。这是一个显示状态随时间变化的 UI 模拟。这是一个下拉菜单(通过 Bootstrap),根菜单项显示当前选择:

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

最终目标是根据用户的选择异步更改页面内容。点击 Bob 应该会触发 handleClick,但不是。

顺便说一句,我对 componentDidMount 调用 this.handleClick(); 的方式不太满意,但它现在可以作为从服务器获取初始菜单内容的一种方式。

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

我几乎可以肯定,我对 javascript 作用域的模糊理解是罪魁祸首,但到目前为止我所尝试的一切都失败了(包括尝试通过 props 传递处理程序)。

【问题讨论】:

    标签: onclick components handler reactjs


    【解决方案1】:

    问题是您正在使用匿名函数创建项目节点,其中this 表示window。解决方法是将.bind(this) 添加到匿名函数中。

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

    或者创建this 的副本并使用它来代替:

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

    【讨论】:

    • 您也可以将map 的第二个参数传递给this,它将用作执行映射函数的上下文。
    • 太棒了。非常感谢!我最终将函数参数分解为map,以使其更具可读性,this 作为第二个参数:var itemNodes = this.state.items.map(this.itemNode, this);
    • @clozach- 如果这回答了你的问题,你能接受吗?
    • @clozach 如果您提取到函数中,则不再需要 map 的上下文 obj - 组件上的所有方法无论如何都会自动绑定到当前实例。所以这可以正常工作:var itemNodes = this.state.items.map(this.itemNode)
    • 这个答案对我来说很棒,简洁易懂,而许多文档似乎是为已经知道的人编写的......TY
    【解决方案2】:

    据我了解“Anna”、“Bob”、“Cal”的任务规范,解决方案可以如下(基于 React 组件和 ES6):

    Basic live demo is here

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-25
      • 1970-01-01
      • 2020-02-01
      • 1970-01-01
      • 2020-10-11
      • 1970-01-01
      • 1970-01-01
      • 2019-04-26
      相关资源
      最近更新 更多