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.pswp.cn/news/393933.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/393933.shtml
英文地址,請注明出處:http://en.pswp.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。牛欄…