React JS onClick事件处理程序


120

我有

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

Answers:


95

为什么不:

onItemClick: function (event) {

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

},

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

而且,如果您希望对此有更多的了解,可以将所选项目设置为其包含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>s放入一个循环中,并且需要将li.onli.off样式设置为background-color


React中的手动DOM操作是一种反模式,只会导致更多问题。避免使用类似的东西,event.currentTarget.style.backgroundColor = '#ccc';除非您真正了解自己在做什么(大多数时候,在集成第三方小部件时)。
Emile Bergeron

61

我能想到的两种方法是

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
不建议将绑定应用到render函数中,因为绑定将在每次渲染组件时进行。您可以将其移至在生命周期开始时运行的某些功能
jony89 '17

1
@ jony89同意,如果.bind不使用额外的参数。但在第一种情况下确实如此。我认为没有其他办法
Dhiraj

1
创建三个不同的函数(这些函数是由getComponent.bind(this,1)的结果创建的),尽管可以肯定地决定(将使用2-3个组件,而不是20个组件-除非这确实是性能问题)并易于动态创建)。
jony89年

38

这是您定义React OnClick 事件处理程序的方式,该处理程序使用es6语法回答问题标题...

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
方法中都不bind应该使用箭头函数,render因为它们每次都会导致创建新函数。这具有更改组件状态的效果,并且始终会重新渲染状态更改的组件。对于一个人来说,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-不,它只是添加一些参数清晰度
itcropper16年

5
这实际上对性能不利,因为它会在每次渲染时创建一个新函数。请参阅:stackoverflow.com/questions/36677733/...
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;

注意,每个动态创建的元素应具有唯一的引用“键”。

此外,如果您想将实际数据对象(而不是事件)传递给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函数会引发错误。

1
我刚刚在需要使用.bind(this))的地方找到了类似的答案。在匿名函数的末尾,因为这里指的是窗口,直到您进行绑定...


6

使用React元素处理事件与处理DOM元素上的事件非常相似。有一些语法上的差异:

  • React事件使用camelCase命名,而不是小写。
  • 使用JSX,您可以传递一个函数作为事件处理程序,而不是字符串。

因此,正如React文档中提到的那样,它们在事件处理方面与普通HTML非常相似,但是在React中使用camelcase的事件名称,因为它们不是真正的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点答案基本相同,并且复活了一个“或”或“为什么”的问题?
戴夫牛顿

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方法。创建您的元素,而不是创建它的克隆。在克隆的创建过程中,您可以注入道具。注入像这样的onClick:方法道具

{ 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

-17

这是一种不使用JSX的非标准(但并非罕见)的React模式,而是将所有内容都内联。另外,它是Coffeescript。

执行此操作的“反应方式”将取决于组件自身的状态:

c = console.log.bind console

mock_items: [
    {
        name: 'item_a'
        uid: shortid()
    }
    {
        name: 'item_b'
        uid: shortid()
    }
    {
        name: 'item_c'
        uid: shortid()
    }
]
getInitialState: ->
    lighted_item: null
render: ->
    div null,
        ul null,
            for item, idx in @mock_items
                uid = item.uid
                li
                    key: uid
                    onClick: do (idx, uid) =>
                        (e) =>
                            # justf to illustrate these are bound in closure by the do lambda,
                            c idx
                            c uid
                            @setState
                                lighted_item: uid
                    style:
                        cursor: 'pointer'
                        background: do (uid) =>
                            c @state.lighted_item
                            c 'and uid', uid
                            if @state.lighted_item is uid then 'magenta' else 'chartreuse'
                        # background: 'chartreuse'
                    item.name

此示例有效-我在本地进行了测试。您可以在我的github上准确查看此示例代码。最初,env仅出于我自己的白板研发目的而本地化,但为此我将其发布到了Github。它可能会在某个时候被覆盖,但是您可以从2016年9月8日起查看提交,以了解情况。

更笼统地说,如果您想了解React的CS / no-JSX模式是如何工作的,请在此处查看最近的工作。我可能有时间为这个应用程序想法完全实现POC,其堆栈包括NodeJS,Primus,Redis和React。


背景不必是dolambda:此表达式还可以使用:background: if @state.lighted_item is uid then 'magenta' else 'chartreuse'
Wylie Kulik

您好,如何在浏览器控制台上查看onclick?
Muneem Habib

12
为什么要在没有以任何方式提及的问题的答案中使用CoffeeScript?这没有任何意义,并且可能会使提问者更难理解答案,因为他可能不知道/喜欢CoffeeScript。显然,令人不快。
Macbem'3

7
不,但这是在语言之上构建的东西,绝对不是标准的,需要安装和编译。当几乎零提示他们在他们的项目中使用咖啡脚本时,用咖啡脚本写您的答案确实是一个糟糕的选择
TheRealMrCrowley

4
Coffeescript只是js 之上的一层。FTFY。
machineghost
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.