React.js 中的 OnClick 事件绑定
Posted
技术标签:
【中文标题】React.js 中的 OnClick 事件绑定【英文标题】:OnClick Event binding in React.js 【发布时间】:2015-02-08 10:14:24 【问题描述】:我想在单击该 div 或同一 div
的任何子元素时传递父 div
id。但我无法实现它。请告诉我我在哪里犯了错误。代码如下:
viewMore: function(i,j)
console.log('You clicked: ', i );
,
render : function()
var attributeId = "groups_";
attributeId+= index;
return(
//parent div
<div className="groups" id=attributeId onClick=this.viewMore>
<div className="floatLeft"> Group Name: <h3>My Name</h3></div>
<span className="floatRight typeCd">POC</span>
<div className="clearfix"> Key Attributes:
<ul>
<li> POC 1</li>
</ul>
</div>
</div>
)
;
【问题讨论】:
【参考方案1】:viewMore = (i,j) => () =>
console.log(i,j)
要将参数传递给事件处理程序,我们需要使用 currying。 使用上述方法,在调用 render 时不会一直创建新函数。
【讨论】:
^^ 只是.bind(null, attributeId)
这也将在每次重新渲染时运行bind
...至少可以说是次优的。
@George Still 会在每次 render
调用时运行 bind
。浪费。最优化的方式,IMO,是在构造函数中进行:this.onclick = this.handleClick.bind(this);
然后,在handleClick
中,从 React 事件中检索 attributeId
:const attributeId = event.target
。
这是一个CodePen 说明该方法。
Zen 是正确的——如果你在组件中使用构造函数,那么渲染方法的污染是不必要的。虽然这个答案有效,甚至可能出现在一些文档示例中,但如果您想最大限度地提高效率,构造函数将更适合您。大多数 React 应用程序的最大问题是渲染方法包含过多的权重,或者在其他情况下未检查触发。【参考方案2】:
由于我在多个地方看到此类建议,我也将把我的评论移到答案中,以提供额外的观点:
class TestComponent extends React.Component
constructor()
super();
this.onClick = this.handleClick.bind(this);
handleClick(event)
const id = event.target;
console.log(id);
render()
return (
<div>
<h3 id=this.props.id onClick=this.onClick>
this.props.name
</h3>
</div>
);
这允许:
-
避免不必要的绑定
以更加 React-ive 的方式访问
id
和任何其他属性。
当然,上面的示例假设您收到 id
作为道具,但您也可以进行必要的操作。
更新 1 -- 2016 年 11 月 28 日
从上面的 cmets 添加了到 CodePen 的链接。
更新 2 -- 2017 年 3 月 30 日
如前所述,如果您使用React.createClass
来定义您的组件,这将不起作用。您没有构造函数来完成此操作。如果你不介意有点丑,你可以使用其他生命周期方法。
话虽如此,现在是 2017 年。使用 ES6,好吗?!
更新 3 -- 2017 年 5 月 12 日
如果你使用class properties transform,那么你可以进一步简化它:
class TestComponent extends React.Component
onClick = (event) =>
const id = event.target;
console.log(id);
render()
return (
<div>
<h3 id=this.props.id onClick=this.onClick>
this.props.name
</h3>
</div>
);
更新 4 -- 2018 年 2 月 4 日
由于 bind
和 V8 中的朋友(可能还有 Chakra 等)的改进,您最好使用 this.click.bind(this)
或在传递给 onClick
时将其包装在箭头函数中。
为什么?
之前的方法仅出于性能原因而创建,关闭了将函数动态注入组件原型的一些可能性。
注意 1 -- 2018 年 4 月 14 日
请记住,更新 4 中提到的方法仍然引入了一些性能问题,因为在每个 render
传递中,由于 bind
的结果创建了一个新函数。这反过来又会渗透到子组件并导致不必要的重新渲染,因为函数每次都会发生变化。
当您内联传递箭头函数时,也会发生同样的事情。
所有其他方法,比如使用类属性,都会弄乱你的继承(你应该避免,但仍然如此),这仅仅是因为,目前,Babel 将它们转换为“实例”函数,这些函数是不在原型链上。
所以,这个:
class Person
printA = () => console.log('a')
变成:
function _classCallCheck(instance, Constructor) ...abridged...
var Person = function Person()
_classCallCheck(this, Person);
this.printA = function ()
console.log('a');
;
;
【讨论】:
这是迄今为止最好的答案,它不仅是一种更有条理的用法,而且它可以防止渲染周期受到污染——更不用说不必要的冗长了。 我使用了类似的方法,但使用了 html5 data-* 属性。处理函数只是做了一个 e.target.attributes['data-XXXX'].value.e.target.dataset.XXXX
会更好,如果这是你的方法。无论如何——以上(在答案中)是 React 对该部分的抽象。
@pikilon“向 JSX 对象添加属性”?那是什么意思?我正在扩展 React 组件的 JS 类上创建一个绑定方法。当然,最好在每次渲染时重新绑定(尽管在 V8 中使用 TurboFan 应该会好得多)。除此之外——这种方式更惯用。
@matanster 你的意思是onClick
作为道具的传递?好吧,我不确定。从render
返回之后,实际的绑定、DOM 和其他东西就会发生。 React 是否每次都重新绑定事件,我不知道。为什么会有这样的担忧?【参考方案3】:
以下是之前答案的更新和概述:
-
@HenrikAndersson 使用 onClick=this.viewMore.bind(this, attributeId)
.虽然这种方法可以达到目的,但它使用了许多人不习惯的绑定语法。
使用@ZenMaster提到的public class field。这个解决方案的性能差不多,但语法也更好。但是当我们必须传递一个参数时,它变得很棘手。
class TestComponent extends React.Component
onClick = (event) =>
const id = event.target;
console.log(id);
render()
return (
<div>
<h3 id=this.props.id onClick=this.onClick>
this.props.name
</h3>
</div>
);
上述方法跳过了传递参数,而是使用自定义属性来访问点击处理程序中所需的数据。
更好的解决方案是:
class MyComponent extends React.Component
handleClick = (item) => (e) =>
e.preventDefault()
console.log(`This has access to item $item! and event(e)`)
render()
const item= id:'1', value: 'a'
return(
<button onClick= this.handleClick(item) >Click</button>
)
参考:Handle events by arrow functions in React app
【讨论】:
【参考方案4】:你可以使用currying函数。
ES5:
viewMore(param) // param is the argument you passed to the function
return function(e) // e is the event object that returned
;
ES6
viewMore = param => e =>
// param is the argument you passed to the function
// e is the event object that returned
;
然后像这样使用它:
onClick=this.viewMore("some param")
【讨论】:
这样,在每次渲染时都会调用该方法,而不仅仅是在您单击它时 @Apperside 真实。虽然在大多数情况下这不是问题(如果您指的是性能) 实际上我指的是如果我在 onClick 侦听器中放入一些东西,也许我希望它在我单击它时被执行。这没有任何意义 @Apperside 这里有 2 个方法,一个是您使用参数调用的外部方法,另一个是作为实际事件侦听器返回的方法。这里的诀窍是第二种方法是关闭参数,这将允许您随心所欲地使用它。事件处理程序将仅在触发事件(在本例中为单击)时调用,而不是在您提到的每个渲染时调用。 我明白你的意思,这实际上是有道理的,我仍然想知道这种方法如何影响内存,因为它在每次渲染时都会创建一个新函数......【参考方案5】:我在这里为 ES6 做了一个更新的答案: https://***.com/a/35748912/76840
本质上,您可以使用箭头函数表达式,它的好处是保留this
:
onClick=(event)=>this.viewMore(attributeId, event)
截至本次编辑,如果您使用启用了 stage-2 的 Babel,您可以使用如下属性:
// Within your class...
viewMore = (event) => /* ... */
// Within render method in your JSX
onClick = this.viewMore
【讨论】:
但这不会产生在每次渲染调用时创建一个新函数对象的负面影响吗? @Aaron_H 确实如此,但其他解决方案如.bind
也是如此。在我看来,它是 1) 文档中推荐的方法之一 (facebook.github.io/react/docs/reusable-components.html),2) 至少在我从事的 React 项目中担心函数创建的微优化。如果你想避免这种情况,你可能需要在组件的构造函数中绑定或分配箭头函数,并在 jsx 中传递函数本身...
或者使用 Babel 的 stage-2 的属性,它仍然更干净。以上是关于React.js 中的 OnClick 事件绑定的主要内容,如果未能解决你的问题,请参考以下文章