如何在 React 子组件中设置事件处理程序

Posted

技术标签:

【中文标题】如何在 React 子组件中设置事件处理程序【英文标题】:How to set event handler in React sub-component 【发布时间】: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 传递处理程序)。

【问题讨论】:

【参考方案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>
    )
  

【讨论】:

以上是关于如何在 React 子组件中设置事件处理程序的主要内容,如果未能解决你的问题,请参考以下文章

vue中设置子组件的点击事件不影响父组件的点击事件

如何在 Django 表单输入字段中设置事件处理程序

如何使用 CSS 模块在 React 中设置子组件的样式

react/flux- 子组件用户事件 - 一切都应该通过调度程序路由吗

如何在服务器端 React 中访问 JSX 组件的 DOM 事件处理程序

React处理点击组件以外区域事件