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 LuzonShesh提到了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中绑定点击事件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值