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

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中绑定点击事件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/393933.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

json_decode php数组,json_decode转化为数组加true,json_encode和json_decode区别

一、json_encode和json_decode区别1、json_encode&#xff1a;对象/数组 ---> json2、json_decode&#xff1a;json ---> 对象/数组二、json_decode转化为数组转化为数组时&#xff0c;第二个参数很重要&#xff1a;不加true会以PHP对象输出, 加true输出PHP数组&#xff…

leetcode1219. 黄金矿工(回溯)

你要开发一座金矿&#xff0c;地质勘测学家已经探明了这座金矿中的资源分布&#xff0c;并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量&#xff1b;如果该单元格是空的&#xff0c;那么就是 0。 为了使收益最大化&#xff0c;矿工…

【无删减】Python老司机收藏夹的17个国外免费学习网站

用Python编写代码一点都不难&#xff0c;事实上它一直被赞誉为最容易学的编程语言。如果你准备学习web开发&#xff0c; Python是一个不错的开始&#xff0c;甚至想做游戏的话&#xff0c;用Python来开发游戏的资源也有很多。这是快速学习这门语言的途径之一。许多程序员都把Py…

iframe vue 前进 后退_vue常见面试题

1、说说你对 SPA 单页面的理解&#xff0c;它的优缺点分别是什么&#xff1f;SPA&#xff08; single-page application &#xff09;仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成&#xff0c;SPA 不会因为用户的操作而进行页面的重新加载或跳转…

C#编写运行在Linux环境下的采用Mediainfo来获取多媒体文件信息的代码

C#编写运行在Linux环境下的采用Mediainfo来获取多媒体文件信息的代码 原文:C#编写运行在Linux环境下的采用Mediainfo来获取多媒体文件信息的代码项目开始设计的是运行在windows下&#xff0c;所以一开始采用的是windows服务模式来获取多媒体文件信息&#xff0c;后来要求调整为…

如何用chrome扩展将网页变成黑底白字,用以保护视力

不知道有没有科学依据&#xff0c;自己感觉黑底白字对视力好些&#xff0c;于是动手加个chrome扩展&#xff1a; 第一步&#xff1a;建个文件夹&#xff0c;名称比如叫changeColor; 第二步&#xff1a;在changeColor文件夹中建三个文件&#xff1a;manifest.json 、 backgrou…

从零学习机器学习_机器学习:如何从零变英雄

从零学习机器学习以“为什么&#xff1f;”开头 并以“我准备好了&#xff01;”结尾 (Start with “Why?” and end with “I’m ready!”) If your understanding of A.I. and Machine Learning is a big question mark, then this is the blog post for you. Here, I gradu…

sqoop动态分区导入mysql,使用sqoop import从mysql往hive含分区表中导入数据的一些注意事项...

先看下面这条语句&#xff0c;它实现的功能是将特定日期的数据从mysql表中直接导入hive$ sqoop import \--connect jdbc:mysql://192.168.xx.xx:3306/db_name?useSSLfalse \--username xxx --password xxxxxx \--query "select d.id, d.callsign, d.sobt from t_flight_b…

leetcode面试题 08.04. 幂集(递归)

幂集。编写一种方法&#xff0c;返回某集合的所有子集。集合中不包含重复的元素。 说明&#xff1a;解集不能包含重复的子集。 示例: 输入&#xff1a; nums [1,2,3] 输出&#xff1a; [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ] 代码 class Solution {List&l…

gatsby_我如何使用Gatsby和Netlify建立博客

gatsbyby Pav Sidhu通过帕夫西杜(Pav Sidhu) 我如何使用Gatsby和Netlify建立博客 (How I Built My Blog Using Gatsby and Netlify) 您能说出更具标志性的二人​​组合吗&#xff1f; &#xff1f; (Can you name a more iconic duo? ?) Years ago, whenever I built a stat…

交叉熵与相对熵

熵的本质是香农信息量()的期望。 现有关于样本集的2个概率分布p和q&#xff0c;其中p为真实分布&#xff0c;q非真实分布。 按照真实分布p来衡量识别一个样本的所需要的编码长度的期望(即平均编码长度)为&#xff1a;H(p)。 如果使用错误分布q来表示来自真实分布p的平均编码长度…

menustrip

在对应菜单上点击鼠标右键&#xff0c;插入&#xff0c;SEPARATOR 就可以了&#xff0c;然后可以选中拖动位置。转载于:https://www.cnblogs.com/Echo529/p/6382302.html

直接排序

题目&#xff1a;使用直接排序法将下列数组&#xff08;从小到大排序&#xff09;思路&#xff1a;第一次&#xff1a;使用索引值为0的元素与其他位置的元素挨个比较一次&#xff0c;如果发现比0号索引值的元素小的&#xff0c;那么交换位置&#xff0c;第一轮下来最小值被放在…

leetcode78. 子集(回溯)

给定一组不含重复元素的整数数组 nums&#xff0c;返回该数组所有可能的子集&#xff08;幂集&#xff09;。 说明&#xff1a;解集不能包含重复的子集。 示例: 输入: nums [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ] 代码 class Solution {pub…

php字符串综合作业,0418php字符串的操作

实例字符串函数(一):长度计算$siteName php中文网;//获取内部字符编码集$encoding mb_internal_encoding();//1、strlen($str):获取字节表示的字符串长度//utf8模式下&#xff0c;一个中文字符用三个字节表示echo strlen($siteName),; //12//2、mb_strlen($str,$encoding)&…

如何处理JavaScript中的事件处理(示例和全部)

In this blog, I will try to make clear the fundamentals of the event handling mechanism in JavaScript, without the help of any external library like Jquery/React/Vue.在此博客中&#xff0c;我将尝试在没有任何外部库(例如Jquery / React / Vue)的帮助下阐明JavaSc…

js 图片预览

//显示选择的图片缩略图function showImage(inputId,imageConfirmId,imageConfi){var imagedocument.getElementById(inputId).value.toLowerCase();if(!image){return;}var fileExtendimage.substr(image.lastIndexOf(".", image.length)1);if(!(fileExtend"jp…

什么是copyonwrite容器

2019独角兽企业重金招聘Python工程师标准>>> CopyOnWrite容器即写时复制的容器。通俗的理解是当往一个容器添加元素的时候&#xff0c;不直接往当前容器添加&#xff0c;而是先将当前容器进行Copy&#xff0c;复制出一个新的容器&#xff0c;然后新的容器里添加元素…

hystrix 源码 线程池隔离_Hystrix源码学习--线程池隔离

分析你的系统你所认识的分布式系统&#xff0c;哪些是可以进行垂直拆分的&#xff1f;拆分之后系统之间的依赖如何梳理&#xff1f;系统异构之后的稳定性调用如何保证&#xff1f;这些都是可能在分布式场景中面临的问题。说个比较常见的问题&#xff0c;大家都知道秒杀系统&…

P2341 [HAOI2006]受欢迎的牛 强连通

题目背景 本题测试数据已修复。 题目描述 每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶 牛都是自恋狂&#xff0c;每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜 欢B&#xff0c;B喜欢C&#xff0c;那么A也喜欢C。牛栏…