React JS 点击事件处理程序

130

我有

var TestApp = React.createClass({
      getComponent: function(){
          console.log(this.props);
      },
      render: function(){
        return(
             <div>
             <ul>
                <li onClick={this.getComponent}>Component 1</li>
             </ul>
             </div>
        );
      }
});
React.renderComponent(<TestApp />, document.body);

我想要在点击的列表元素上着色背景。在React中我该如何实现?

类似于:

$('li').on('click', function(){
    $(this).css({'background-color': '#ccc'});
});
11个回答

104

为什么不呢:

onItemClick: function (event) {

    event.currentTarget.style.backgroundColor = '#ccc';

},

render: function() {
    return (
        <div>
            <ul>
                <li onClick={this.onItemClick}>Component 1</li>
            </ul>
        </div>
    );
}

如果你希望更加 React-ive,你可能希望将所选项目设置为其包含的 React 组件的状态,然后在 render 中引用该状态来确定项目的颜色:

onItemClick: function (event) {

    this.setState({ selectedItem: event.currentTarget.dataset.id });
    //where 'id' =  whatever suffix you give the data-* li attribute
},

render: function() {
    return (
        <div>
            <ul>
                <li onClick={this.onItemClick} data-id="1" className={this.state.selectedItem == 1 ? "on" : "off"}>Component 1</li>
                <li onClick={this.onItemClick} data-id="2" className={this.state.selectedItem == 2 ? "on" : "off"}>Component 2</li>
                <li onClick={this.onItemClick} data-id="3" className={this.state.selectedItem == 3 ? "on" : "off"}>Component 3</li>
            </ul>
        </div>
    );
},

你需要将这些<li>放进一个循环中,并且需要使li.onli.off样式设置为你的background-color


2
在React中手动操作DOM是一种反模式,这只会导致更多的问题。除非你真正理解自己在做什么(大多数情况下是在集成第三方小部件),否则避免使用像event.currentTarget.style.backgroundColor = '#ccc';这样的东西。 - Emile Bergeron

62

我能想到的两种方法是

var TestApp = React.createClass({
    getComponent: function(index) {
        $(this.getDOMNode()).find('li:nth-child(' + index + ')').css({
            'background-color': '#ccc'
        });
    },
    render: function() {
        return (
            <div>
              <ul>
                <li onClick={this.getComponent.bind(this, 1)}>Component 1</li>
                <li onClick={this.getComponent.bind(this, 2)}>Component 2</li>
                <li onClick={this.getComponent.bind(this, 3)}>Component 3</li>
              </ul>
            </div>
        );
    }
});
React.renderComponent(<TestApp /> , document.getElementById('soln1'));

这是我的个人最爱。

var ListItem = React.createClass({
    getInitialState: function() {
        return {
            isSelected: false
        };
    },
    handleClick: function() {
        this.setState({
            isSelected: true
        })
    },
    render: function() {
        var isSelected = this.state.isSelected;
        var style = {
            'background-color': ''
        };
        if (isSelected) {
            style = {
                'background-color': '#ccc'
            };
        }
        return (
            <li onClick={this.handleClick} style={style}>{this.props.content}</li>
        );
    }
});

var TestApp2 = React.createClass({
    getComponent: function(index) {
        $(this.getDOMNode()).find('li:nth-child(' + index + ')').css({
            'background-color': '#ccc'
        });
    },
    render: function() {
        return (
            <div>
             <ul>
              <ListItem content="Component 1" />
              <ListItem content="Component 2" />
              <ListItem content="Component 3" />
             </ul>
            </div>
        );
    }
});
React.renderComponent(<TestApp2 /> , document.getElementById('soln2'));

这里有一个示例

希望这能帮到您。


8
不建议在渲染函数中使用bind,因为这会导致每次组件渲染时都执行一次。你可以将它移到某个在生命周期开始时运行的函数中。 - jony89
1
@jony89同意如果.bind不带额外参数。但在第一种情况下,它确实需要。我认为没有其他方法。 - Dhiraj
1
有一个需求,需要创建三个不同的函数(这些函数是通过getComponent.bind(this, 1)的结果创建的),尽管这肯定可以是一个决策(如果只涉及2-3个组件,可以这样做,但如果涉及20个组件,除非真的存在性能问题并且可以轻松地动态创建它,否则不建议这样做)。 - jony89

39

以下是使用 ES6 语法定义一个 React onClick 事件处理程序,以回答标题中的问题:

import React, { Component } from 'react';

export default class Test extends Component {
  handleClick(e) {
    e.preventDefault()
    console.log(e.target)
  }

  render() {
    return (
      <a href='#' onClick={e => this.handleClick(e)}>click me</a>
    )
  }
}

9
render方法中不应使用bind或箭头函数,因为这会导致每次创建一个新的函数。这会改变组件的状态,状态发生改变的组件总是被重新渲染。对于单个a来说,这没什么大不了的影响。但对于具有可点击项目的生成列表来说,这很快就成为一个大问题。这就是为什么需要特别警告的原因。 - hippietrail

18

使用ECMA2015。箭头函数使得"this"更加直观易懂。

import React from 'react';


class TestApp extends React.Component {
   getComponent(e, index) {
       $(e.target).css({
           'background-color': '#ccc'
       });
   }
   render() {
       return (
           <div>
             <ul>
               <li onClick={(e) => this.getComponent(e, 1)}>Component 1</li>
               <li onClick={(e) => this.getComponent(e, 2)}>Component 2</li>
               <li onClick={(e) => this.getComponent(e, 3)}>Component 3</li>
             </ul>
           </div>
       );
   }
});
React.renderComponent(<TestApp /> , document.getElementById('soln1'));`

2
这里的 index 没有任何作用? - northamerican
@northamerican - 不是的,它只是为了增加一些参数清晰度。 - itcropper
5
这实际上会影响性能,因为它会在每次渲染时创建一个新函数。参见: https://dev59.com/MFoV5IYBdhLWcg3wIbtT - Jochie Nabuurs
1
如果不必要,请勿在React中使用jQuery! - Emile Bergeron

13

如果您正在使用ES6,这里有一些简单的示例代码:

import React from 'wherever_react_is';

class TestApp extends React.Component {

  getComponent(event) {
      console.log('li item clicked!');
      event.currentTarget.style.backgroundColor = '#ccc';
  }

  render() {
    return(
       <div>
         <ul>
            <li onClick={this.getComponent.bind(this)}>Component 1</li>
         </ul>
       </div>
    );
  }
}

export default TestApp;

在ES6类的主体中,函数不再需要使用'function'关键字,并且它们不需要用逗号分隔。如果您希望,您也可以使用=>语法。

以下是一个使用动态创建元素的示例:

import React from 'wherever_react_is';

class TestApp extends React.Component {

constructor(props) {
  super(props);

  this.state = {
    data: [
      {name: 'Name 1', id: 123},
      {name: 'Name 2', id: 456}
    ]
  }
}

  getComponent(event) {
      console.log('li item clicked!');
      event.currentTarget.style.backgroundColor = '#ccc';
  }

  render() {        
       <div>
         <ul>
         {this.state.data.map(d => {
           return(
              <li key={d.id} onClick={this.getComponent.bind(this)}>{d.name}</li>
           )}
         )}
         </ul>
       </div>
    );
  }
}

export default TestApp;

请注意,每个动态创建的元素都应该有一个唯一的引用“key”。

另外,如果您想将实际的数据对象(而不是事件)传递到onClick函数中,您需要将其传递到绑定中。例如:

新的onClick函数:

getComponent(object) {
    console.log(object.name);
}

传入数据对象:

{this.state.data.map(d => {
    return(
      <li key={d.id} onClick={this.getComponent.bind(this, d)}>{d.name}</li>
    )}
)}

我正在尝试动态构建我的li项,但是它似乎变成了未定义的,因此onClick函数会抛出错误。 - landed
1
我刚找到一个类似的答案,其中需要在匿名函数的末尾使用.bind(this));,因为在这里,this指的是窗口,直到你进行绑定... - landed
1
不,你在JSX中永远不应该使用bind或箭头函数。 - hippietrail

6
处理 React 元素 的事件与处理 DOM 元素的事件非常相似。但是有一些语法上的区别:
  • React 事件采用驼峰式命名,而不是小写字母。
  • 使用 JSX 时,将函数作为事件处理程序传递,而不是字符串。
因此,正如 React 文档中提到的那样,当涉及到事件处理时,它们与普通 HTML 相似,但在 React 中,事件名使用驼峰式命名,因为它们实际上不是 HTML,而是 JavaScript。此外,你要传递一个函数,而在 HTML 中,我们将函数调用以字符串格式传递。虽然它们有所不同,但概念上非常类似...
请查看下面的示例,注意将事件传递给函数的方式:
function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

3

import React from 'react';

class MyComponent extends React.Component {

  getComponent(event) {
      event.target.style.backgroundColor = '#ccc';
      
      // or you can write
      //arguments[0].target.style.backgroundColor = '#ccc';
  }

  render() {
    return(
       <div>
         <ul>
            <li onClick={this.getComponent.bind(this)}>Component 1</li>
         </ul>
       </div>
    );
  }
}

export { MyComponent };  // use this to be possible in future imports with {} like: import {MyComponent} from './MyComponent'
export default MyComponent;


这似乎与11点答案本质上相同,并且提出了一个漂亮的问题-为什么? - Dave Newton

2

class FrontendSkillList extends React.Component {
  constructor() {
    super();
    this.state = { selectedSkill: {} };
  }
  render() {
    return (
      <ul>
        {this.props.skills.map((skill, i) => (
            <li
              className={
                this.state.selectedSkill.id === skill.id ? "selected" : ""
              }
              onClick={this.selectSkill.bind(this, skill)}
              style={{ cursor: "pointer" }}
              key={skill.id}
            >
            {skill.name}
            </li>
        ))}
      </ul>
    );
  }

  selectSkill(selected) {
    if (selected.id !== this.state.selectedSkill.id) {
      this.setState({ selectedSkill: selected });
    } else {
      this.setState({ selectedSkill: {} });
    }
  }
}

const data = [
  { id: "1", name: "HTML5" },
  { id: "2", name: "CSS3" },
  { id: "3", name: "ES6 & ES7" }
];
const element = (
  <div>
    <h1>Frontend Skill List</h1>
    <FrontendSkillList skills={data} />
  </div>
);
ReactDOM.render(element, document.getElementById("root"));
.selected {
  background-color: rgba(217, 83, 79, 0.8);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>

@user544079 希望这个演示能有所帮助 :) 我建议通过切换类名来更改背景颜色。


2

import React from 'react';

class MyComponent extends React.Component {

  getComponent(event) {
      event.target.style.backgroundColor = '#ccc';
      
      // or you can write
      //arguments[0].target.style.backgroundColor = '#ccc';
  }

  render() {
    return(
       <div>
         <ul>
            <li onClick={this.getComponent.bind(this)}>Component 1</li>
         </ul>
       </div>
    );
  }
}

export { MyComponent };  // use this to be possible in future imports with {} like: import {MyComponent} from './MyComponent'
export default MyComponent;


你能否提供更多上下文来解释这段代码如何解决问题? - MEDZ

1
您可以使用React.createClone方法。创建您的元素,然后创建它的克隆。在克隆创建期间,您可以注入props。像这样注入一个onClick : method prop

{ onClick : () => this.changeColor(originalElement, index) }

changeColor方法将使用副本设置状态,从而允许您在过程中设置颜色。

render()
  {
    return(
      <ul>

        {this.state.items.map((val, ind) => {
          let item = <li key={ind}>{val}</li>;
          let props = { 
            onClick: () => this.Click(item, ind),
            key : ind,
            ind
          }
          let clone = React.cloneElement(item, props, [val]);
          return clone;
        })}

      </ul>
    )
  }


克隆是完全不必要的。 - Emile Bergeron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接