在react处理外部方法
*“Property Initializer Syntax”* sounds more fancy than it really is. In this bite-sized tutorial see how this alternative way of writing event handlers will help eliminate boilerplate in your constructor
and also defend against frivolous memory usage in your renders.
*“ Property Initializer Syntax”(属性初始化器语法)*听起来比实际的要花哨。 在这本篇幅如此短的教程中,您将看到这种编写事件处理程序的替代方法将如何帮助消除constructor
样板,并防止渲染中的琐碎内存使用。
In the Facebook docs, you’ll see event handling done like this:
在Facebook文档中,您将看到事件处理如下:
// option 1
class Thing extends React.Component {
constructor() {
this.handleSmthng = this.handleSmthng.bind(this)
}
render() {
<input onChange={this.handleSmthng}/>
}
handleSmthng(e) {
// ...
}
}
ES6 classes won’t automatically give this
scope to handleSmthng
, and since you’ll usually want to call this.setState
or perhaps invoke another method in the component, the “official” convention is to bind all the event handlers all the time in constructor. This works, but can quickly feel like boilerplate code.
ES6类不会自动this
范围赋予handleSmthng
,并且由于您通常要调用this.setState
或调用组件中的另一个方法,因此“正式”约定是始终将所有事件处理程序绑定到构造函数中 。 这可行,但是很快就会感觉像样板代码。
// option 2
class Thing extends React.Component {
render() {
<button onClick={() => this.handleSmthng('foo')}>
ADD
</button>
}
handleSmthng(arg1) {
// ...
}
}
This pattern seems to be getting popular in React tutorials online. It will pass this
context to handleSmthng
and it avoids boilerplate code in the constructor. Heck, there’s no state in this component so you don’t even need a constructor! I think the motivations for this approach are right… but there’s a slight performance cost.
这种模式在在线React教程中似乎越来越流行。 它将this
上下文传递给handleSmthng
,并且避免了构造函数中的样板代码。 哎呀,此组件中没有任何状态,因此您甚至不需要构造函数! 我认为采用这种方法的动机是正确的……但是这会降低性能成本。
Using an arrow function will always create a new reference in JavaScript which, in turn, increases memory usage for your apps. While memory is cheap in JavaScript, renders are costly in React. When you pass arrow functions to child components, your child component will indiscriminately re-render since (as far as it’s concerned) that arrow function is new data. This could mean the difference between getting 60fps or 50fps for large React applications.
使用箭头功能将始终在JavaScript中创建新的引用,从而增加应用程序的内存使用量。 虽然在JavaScript中内存便宜,但在React中渲染成本很高。 当您将箭头函数传递给子组件时,由于(就其而言)箭头函数是新数据,因此您的子组件将被任意渲染。 对于大型React应用程序,这可能意味着获得60fps或50fps。
“…However if this callback is passed as a prop to lower components, those components might do extra re-rendering.” React Docs
“…但是,如果此回调作为对较低组件的支持而传递,则这些组件可能会进行额外的重新渲染。” React文档
两结合一封闭 (Two Binds One Closure)
There’s a much cleaner way to write event handlers that 1) avoids boilerplate and 2) doesn’t cause extra re-renders: property initializer syntax! It’s a fancy name, but the idea is really simple… just use arrow functions to define your event handlers. Like this:
有一种更简洁的事件处理程序编写方式:1)避免样板操作,2)不会引起额外的重新渲染: 属性初始化器语法 ! 这是一个花哨的名字,但是这个想法很简单……只需使用箭头函数定义事件处理程序即可。 像这样:
class TodoApp extends React.Component {
render() {
return (
<div>
<button onClick={this.handleClick}>
ADD
</button>
<input onChange={this.handleInput}/>
</div>
);
}
handleClick = () => {
// "this"
}
handleInput = (e) => {
// "this", "e"
}
}
You defined two handlers, and it’s looking really nice. No boilerplate. Easy to read. Easy to re-factor… if you want to pass arguments:
您定义了两个处理程序,看起来非常不错。 没有样板。 易于阅读。 易于重构……如果您想传递参数:
class TodoApp extends React.Component {
render() {
return (
<div>
<button onClick={this.handleClick}>
ADD
</button>
<input onChange={this.handleInput}/>
{
this.state.todos.map((item) => {
return (
<li onClick={this.handleRemove(item.id)}>
{item.text}
</li>
);
});
}
</div>
)
}
handleClick = () => {
// "this"
}
handleInput = (e) => {
// "this", "e"
}
handleRemove = (id) => (e) => {
// "this", "e", "id"
}
}
Boom! You can pass arguments without using bind
in your render methods, or your constructor! Everything looks really spick and span.
繁荣! 您可以在不使用render方法或构造函数中使用bind
情况下传递参数! 一切看起来都很细腻。
If you’re not used to seeing arrow functions this probably looks weird. Remember with ES6 that the fat arrow syntax allows omitting curly braces for one-line statements… it’ll implicitly return
whatevers on that line! This is how Babel would transpile handleRemove
:
如果您不习惯看到箭头功能,这可能看起来很奇怪。 记住,在ES6中,粗箭头语法允许省略单行语句的花括号 ……它将隐式return
该行的所有内容! 这是Babel如何转换handleRemove
:
handleRemove: function (item) {
return function (e) {
// "item" AND "e" 🌈
}
}
To configure Babel to use Property Initializer Syntax, make sure you’ve installed the “transform-class-properties” plugin or enable stage-2. If you’re using “create-react-app”… it’s already there!
要将Babel配置为使用Property Initializer语法,请确保已安装“ transform-class-properties”插件或启用stage-2 。 如果您使用的是“ create-react-app”……它已经存在!
There’s an ESLint rule that will tell you not to use “bind” or arrow functions in render
有一条ESLint规则 ,该规则将告诉您不要在渲染中使用“绑定”或箭头功能
使用属性初始化器语法的好处 (Benefits of Using Property Initializer Syntax)
My best guess that Facebook hasn’t “officially” endorsed this pattern in their documentation is because stage-2 ES6 hasn’t been finalized yet, so Property Initializers are still considered non-standards. However, the create-react-app
generator already enables stage-2 so… it’s very likely Property Initializers will become de-facto for defining event handlers in the near future.
我最好的猜测是Facebook尚未在其文档中“正式”认可这种模式,因为第二阶段ES6尚未完成,因此Property Initializers仍被视为非标准。 但是, create-react-app
生成器已经启用了stage-2,因此...很可能在不久的将来,属性初始化器将成为定义事件处理程序的事实。
Once you get comfortable with Property Initializers and begin using them to define handler methods, you’ll gain two notable benefits:
一旦熟悉了属性初始化器并开始使用它们来定义处理程序方法,您将获得两个显着的好处:
Less boilerplate to write Not having to write
bind
statements in the constructor is pretty sweet. Now you just define the method––and that’s it ✨. If you need to pass arguments, just wrap with a single closure and remember to invoke that handler function inrender
. As an added benefit, if you need refactor your event handler somewhere else, you only got one place to cut-paste from.编写更少的样板程序不必在构造函数中编写
bind
语句,这非常好。 现在,您只需定义方法-就是这样。 如果需要传递参数,只需用一个闭包包装,并记住在render
调用该处理函数。 另外一个好处是,如果您需要在其他地方重构事件处理程序,则只能从一个地方剪切粘贴。Lower memory usage Using arrow functions in
render
is a bad idea because “by design” renders occur at high volume during a component’s lifecycle; allocating a new pointer for every arrow function. Abstaining from arrow functions inrender
will ensure you’re keeping your component’s memory usage on a diet.降低内存使用率在
render
使用箭头功能不是一个好主意,因为“按设计”渲染在组件的生命周期中会大量出现。 为每个箭头功能分配一个新的指针。 放弃render
箭头功能将确保您节食组件的内存使用情况。
Check out this CodePen to see Property Initializer Syntax in action
翻译自: https://www.digitalocean.com/community/tutorials/react-new-way-to-handle-events
在react处理外部方法