react中绑定点击事件

by Charlee Li

通过李李

在React中绑定事件处理程序的最佳方法 (The best way to bind event handlers in React)

Binding event handlers in React can be tricky (you have JavaScript to thank for that). For those who know the history of Perl and Python, TMTOWTDI (There’s More Than One Way To Do It) and TOOWTDI (There’s Only One Way To Do It) should be familiar words. Unfortunately, at least for event binding, JavaScript is a TMTOWTDI language, which always makes developers confused.

在React中绑定事件处理程序可能很棘手(为此,您需要使用JavaScript)。 对于那些了解Perl和Python历史的人来说,TMTOWTDI(不止一种方法)和TOOWTDI(只有一种方法)应该是熟悉的词。 不幸的是,至少对于事件绑定,JavaScript是一种TMTOWTDI语言,它总是使开发人员感到困惑。

In this post, we will explore the common ways of creating event bindings in React, and I’ll show you their pros and cons. And most importantly, I will help you find the “Only One Way” — or at least, my favorite.

在本文中,我们将探讨在React中创建事件绑定的常见方法,我将向您展示它们的优缺点。 最重要的是,我将帮助您找到“唯一的方式”,或者至少是我的最爱。

This post assumes that you understand the necessity of binding, such as why we need to do this.handler.bind(this), or the difference between function() { console.log(this); } and () => { console.log(this); }. If you get confused about these questions, Saurabh Misra had an amazing post explaining them.

这篇文章假定您了解绑定的必要性,例如为什么我们需要执行this.handler.bind(this)function() { console.log(this); } function() { console.log(this); }() => { console.log(this) ; }。 如果您对这些问题感到困惑,Saurabh Misra会给您一个惊人的解释。

render()中的动态绑定 (Dynamic binding in render())

The first case commonly used is calling .bind(this) in the render() function. For example:

常用的第一种情况是在render()函数中调用.bind(this) 。 例如:

class HelloWorld extends Component {  handleClick(event) {}  render() {    return (      <p>Hello, {this.state.name}!</p>      <button onClick={this.handleClick.bind(this)}>Click</button>    );  }}

Of course this will work. But think about one thing: What happens if this.state.namechanges?

当然可以。 但是请考虑一件事:如果this.state.name更改,会发生什么?

You might say that changing this.state.name will cause the component to re-render() . Good. The component will render to update the name part. But will the button be rendered?

您可能会说更改this.state.name会导致组件重新render() 。 好。 组件将渲染以更新名称部分。 但是按钮会被渲染吗?

Consider the fact that React uses the Virtual DOM. When render occurs, it will compare the updated Virtual DOM with the previous Virtual DOM, and then only update the changed elements to the actual DOM tree.

考虑一下React使用虚拟DOM的事实。 进行渲染时,它将比较更新的虚拟DOM与先前的虚拟DOM,然后仅将更改的元素更新为实际的DOM树。

In our case, when render() is called, this.handleClick.bind(this) will be called as well to bind the handler. This call will generate a brand-new handler, which is completely different than the handler used when render() was called the first time!

在我们的例子中,当调用render()也会调用this.handleClick.bind(this)绑定处理程序。 此调用将生成一个全新的处理程序 ,该处理程序与第一次调用render()时使用的处理程序完全不同!

As in the above diagram, when render() was called previously, this.handleClick.bind(this) returned funcA so that React knew onChange was funcA.

如上图所示,当先前调用render()时, this.handleClick.bind(this)返回funcA以便React知道onChangefuncA

Later, when render() is called again, this.handleClick.bind(this) returned funcB (note it returns a new function every time being called). This way, React knows that onChange is no longer funcA, which means that button needs to be re-rendered.

稍后,当再次调用render()时, this.handleClick.bind(this)返回funcB (请注意,每次调用它都会返回一个新函数)。 这样,React知道onChange不再是funcA ,这意味着需要重新渲染button

One button may not be a problem. But what if you have 100 buttons rendered within a list?

一个按钮可能不是问题。 但是,如果列表中有100个按钮呈现该怎么办?

render() {  return (    {this.state.buttons.map(btn => (      <button key={btn.id} onChange={this.handleClick.bind(this)}>        {btn.label}      </button>    ))}  );}

In the above example, any button label change will cause all the buttons to be re-rendered, since all buttons will generate a new onChange handler.

在上面的示例中,任何按钮标签的更改都将导致所有按钮被重新呈现,因为所有按钮都将生成一个新的onChange处理程序。

绑定在构造函数中 (Bind in constructor())

An old school way is to do the binding in the constructor. Nothing fancy:

一种古老的方法是在构造函数中进行绑定。 没有什么花哨:

class HelloWorld extends Component {  constructor() {    this.handleClick = this.handleClickFunc.bind(this);  }  render() {    return (<button onClick={this.handleClick}/>);  }}

This way is much better than previous one. Calling render() will not generate a new handler for onClick, so the <button> will not be re-rendered as long as the button does not change.

这种方法比以前的方法好得多。 调用render()不会为onClick生成新的处理程序,因此只要按钮不发生变化, <butt on>就不会重新呈现。

与箭头功能绑定 (Bind with the Arrow Function)

With ES7 class properties (currently supported with Babel), we can do bindings at the method definition:

使用ES7类属性(当前受Babel支持),我们可以在方法定义处进行绑定:

class HelloWorld extends Component {  handleClick = (event) => {    console.log(this.state.name);  }  render() {    return (<button onClick={this.handleClick}/>)  }}

In the above code, handleClick is an assignment which is equivalent to:

在上面的代码中, handleClick是等效于:

constructor() {  this.handleClick = (event) => { ... };}

So once the component is initialized, this.handleClick will never change again. This way, it ensures that <button> won’t get re-rendered. This approach is probably the best way of doing bindings. It’s simple, easy to read, and most importantly, it works.

因此,一旦组件初始化, this.handleClick将不再更改。 这样,可以确保<butt on>不会被重新渲染。 这种方法可能是进行绑定的最佳方法。 它简单,易于阅读,最重要的是,它可以工作。

使用箭头功能动态绑定多个元素 (Dynamic binding with the Arrow Function for multiple elements)

Using the same arrow function trick, we can use the same handler for multiple inputs:

使用相同的arrow函数技巧,我们可以对多个输入使用相同的处理程序:

class HelloWorld extends Component {  handleChange = name => event => {    this.setState({ [name]: event.target.value });  }  render() {    return (      <input onChange={this.handleChange('name')}/>      <input onChange={this.handleChange('description')}/>    )  }}

At first glance, this looks pretty amazing due to its simplicity. However, if you consider carefully, you’ll find that it has the same problem as the first approach: every time render() is called both<input> will be re-rendered.

乍看之下,由于其简单性,这看起来非常惊人。 但是,如果仔细考虑,您会发现它与第一种方法存在相同的问题:每次调用render() ,两个<inp ut>都将被重新渲染。

Indeed I do think this approach is smart, and I don’t want to write multiple handleXXXChange for each field either. Luckily, this type of “multi-use handler” is less likely to appear inside a list. This means that there will be only a couple of <input> components that get re-rendered, and there probably won’t be a performance issue.

确实,我确实认为这种方法很聪明,而且我也不想为每个字段编写多个handleXXXChange 。 幸运的是,这种类型的“多用途处理程序”不太可能出现在列表中。 这意味着将只重新渲染几个<inp ut>组件,并且可能不会出现性能问题。

Anyway, the benefits it brings to us are much greater than the performance loss. Therefore, I would suggest that you use this approach directly.

无论如何,它给我们带来的好处远大于性能损失。 因此,我建议您直接使用此方法。

In case those performance issues becoming significant, I would suggest caching the handlers when doing the bindings (but this will make the code less readable):

如果这些性能问题变得很重要,我建议在进行绑定时将处理程序缓存(但这会使代码的可读性降低):

class HelloWorld extends Component {  handleChange = name => {    if (!this.handlers[name]) {      this.handlers[name] = event => {        this.setState({ [name]: event.target.value });      };    }    return this.handlers[name];    }   render() {    return (      <input onChange={this.handleChange('name')}/>      <input onChange={this.handleChange('description')}/>    )  }}

结论 (Conclusion)

When doing event bindings in React, we must check very carefully whether the handlers are generated dynamically. Usually this is not a problem when the affected components appear only once or twice. But when event handlers appear in a list, this can results in severe performance issues.

在React中进行事件绑定时,我们必须非常仔细地检查处理程序是否动态生成。 通常,当受影响的组件仅出现一次或两次时,这不是问题。 但是,如果事件处理程序出现在列表中,则可能导致严重的性能问题。

解决方案 (Solutions)

  • Use Arrow Function binding whenever possible尽可能使用箭头功能绑定
  • If you must generate bindings dynamically, consider caching the handlers if the bindings become a performance issue如果必须动态生成绑定,请考虑在绑定成为性能问题时缓存处理程序

Thanks for reading! I hope this post was helpful. If you find this post useful, please share it with more people by recommending it.

谢谢阅读! 希望这篇文章对您有所帮助。 如果您发现此帖子有用,请通过推荐与更多人分享。

Update:

更新:

Omri Luzon and Shesh mentioned lodash-decorators and react-autobind packages for more convenient bindings. Personally I am not a big fan of automatically doing anything (I am always trying to keep things such bindings minimal) but auto bind is absolutely a great way of writing clean code and saving more efforts. The code would be like:

Omri Luzon和Shesh提到了lodash-decoratorsreact-autobind包,以实现更方便的绑定。 就我个人而言,我并不喜欢自动执行任何操作(我一直在努力使绑定等内容最小化),但是自动绑定绝对是编写简洁代码并节省更多精力的好方法。 代码如下:

import autoBind from 'react-autobind';class HelloWorld() {  constructor() {    autoBind(this);  }
handleClick() {    ...  }  render() {    return (<button onClick={this.handleClick}/>);  }}

Since autoBind will handle the bindings automatically, it is not necessary to use arrow function trick ( handleClick = () => {} ) to do the binding, and in the render() function, this.handleClick can be used directly.

由于autoBind会自动处理的绑定,则没有必要使用箭头功能特技( handleClick = () => {})做的结合,并在吨he rende R()函数的n, this.handleCl可以使用ICK直。

翻译自: https://www.freecodecamp.org/news/the-best-way-to-bind-event-handlers-in-react-282db2cf1530/

react中绑定点击事件

react中绑定点击事件_在React中绑定事件处理程序的最佳方法相关推荐

  1. java弹窗 触发事件_关于ElementUI中MessageBox弹框的取消键盘触发事件(enter,esc)关闭弹窗(执行事件)的解决方法...

    好久没见了 在项目中遇到一个小小的需求,总结了一下! 详细我就不介绍了,相信大家用过的话,很了解.详见文档-----------> http://element-cn.eleme.io/#/zh ...

  2. 移动端 关闭浏览器事件_前端开发中什么是移动端点透事件?

    点透事件:是指两个元素其中一个元素具有默认的点击事件,当我们让不具有点击事件的元素隐藏起来,会触发另一个元素的点击事件,这种行为被称之为点透事件. 如下图所示:当我们给div元素添加touchstar ...

  3. java获取页面点击次数_在Java中怎样得出一个按钮点击的次数

    展开全部 java中得出一个按钮点击的次数,可以使用临时变量32313133353236313431303231363533e58685e5aeb931333337616566来保存点击的次数,在监听 ...

  4. vue输入框输入触发事件_.vue文件中监听input输入事件oninput详解

    .vue文件其实是一个组件,关于它的说明我之前也写过一篇文章,地址:.vue文件,今天这篇文章要讲的是.vue文件中监听input的输入值变化事件.需求是这页面中,改变input的值,就调用一个事件, ...

  5. angularjs中按回车事件_在AutoCAD中巧用空格键或回车键,制图效率高

    AutoCAD在很多行业都有应用,学会AutoCAD多少有些用处.下面介绍以下关于应用空格键或回车键的几个常用技巧,懂得应用的话,制图效率会提升. (1)巧用空格键与回车键重复上一个命令 在完成一个制 ...

  6. 在jQuery中删除事件处理程序的最佳方法?

    我有一个input type="image" . 这就像Microsoft Excel中的单元格注释一样. 如果有人在与该input-image配对的文本框中input-image ...

  7. js阻止子元素事件_阻止 JS 的冒泡事件

    用了一段时间google inbox,赶脚mail task的样式很酷炫,于是也模仿着做了一个task管理系统. Google task有个behavior是点击页面别处,当前展开的mail就会收起. ...

  8. python中numpy数组的合并_基于Python中numpy数组的合并实例讲解

    基于Python中numpy数组的合并实例讲解 Python中numpy数组的合并有很多方法,如 - np.append() - np.concatenate() - np.stack() - np. ...

  9. excel中显示隐藏的行_在Excel中显示或隐藏用户提示

    excel中显示隐藏的行 When you set up a worksheet for other people to use, data validation messages can help ...

最新文章

  1. git stash 个人理解
  2. JAVA设计模式之装饰模式
  3. 如何用html5编写彩色同心圆,HTML5 canvas 同心圆动画
  4. 深入掌握JMS(五):实战Topic
  5. 考勤信息管理系统 需求说明
  6. 2020年海南大学计算机调剂,2020年海南大学招收调剂生
  7. 如何查询Linux服务的作用
  8. 修改jupyter notebook的默认工作路径
  9. git入门-----远程操作相关命令(remote 、push、fetch 、pull)
  10. 无线连接网络找不到计算机组,无线网络连接不见了的4个解决方法!电脑无线网络连接找不到如何解决?...
  11. 关于ArcGIS的入门建议
  12. iOS XCode支持低系统版本
  13. 【鼠标右键点击桌面图标时,出现资源管理器未响应】
  14. root下备份mysql_如何用指令行备份mysql下所有数据库
  15. Java编程专题思维导图
  16. Python自制恶搞virus
  17. CCF 201712-4 行车路线
  18. python版openvino使用
  19. 【xcode】Xcode常用快捷键与技巧
  20. Laplace变换笔记(2)

热门文章

  1. c语言 大雨 班上多个同学准备,2015年计算机二级考试《C语言》提高练习题(7)
  2. (poj)1064 Cable master 二分+精度
  3. Android Sutido 编译速度优化
  4. 对于我今后人生受益匪浅的几句话
  5. JVM初探:内存分配、GC原理与垃圾收集器
  6. 画了个Android
  7. xpath之string(.)方法
  8. Python基础:搭建开发环境(1)
  9. SQLServer之函数简介 1
  10. Linux安装source-code-pro字体