周围有很多答案,但人们总是感到困惑。我知道这一点是因为不久前我曾经感到困惑。一段时间后,我掌握了这些概念。
- 手动绑定对象/函数以便使用状态或道具
在函数内部并避免与作用域相关的问题
不完全正确。您不需要绑定函数来使用状态或道具。您将函数绑定到this
当你失去时this
范围内的上下文。例如在回调函数中。
class App extends React.Component {
state = {
name: "foo",
}
aFunction() {
console.log( this.state.name );
}
render() {
return <div>{this.aFunction()}</div>;
}
}
您不需要绑定您的函数,因为this
指出你的班级,并且你不会失去它的背景。但是,如果您在回调中使用函数(例如按钮),则必须绑定它:
class App extends React.Component {
state = {
name: "foo",
}
aFunction() {
console.log( this.state.name );
}
render() {
return (
<div>
<button onClick={this.aFunction}>Click</button>
</div>
);
}
}
这不起作用,因为你失去了上下文。现在,您需要以某种方式恢复它的上下文,对吗?好的,让我们看看如何做到这一点。首先,我想将它绑定在按钮回调中。
<button onClick={this.aFunction.bind(this)}>Click</button>
是的,这有效。但是,它将在每次渲染中重新创建。所以:
- 始终在构造函数中绑定对象/函数,但不直接在渲染中绑定对象/函数
是的。不要像我上面那样绑定它,而是在你的构造函数中进行。
如果您在构造函数中执行此操作,则 Webpack 仅在组件创建时在 bundle.js 文件中创建一次新对象/函数
第一次渲染
如果你直接在渲染中执行此操作,那么每次组件渲染时,Webpack 都会在 bundle.js 文件中创建一个新的对象/函数
并重新渲染
您在这里总结了我迄今为止试图解释的内容。但是,我想 Webpack 不是这样做的,而是你的应用程序。
- 如果不绑定,则无法访问状态或道具。您必须将当前对象分配给局部变量,否则 this.state 或
this.props 未定义
同样,如果您在类范围内使用函数,则不必绑定它。如果您在类之外使用此函数(例如按钮回调),则必须绑定它。这与以下无关state
or props
。这与使用有关this
.
绑定的第二个选项是使用常规函数在构造函数中进行绑定,第三个选项是使用不绑定的箭头函数。
现在,箭头函数。
1.不需要在构造函数和渲染中绑定对象/函数
Yes.
- 您无需依赖当前对象的局部变量,即 let that = this;
Yes.
- 您不会遇到范围问题,并且对象/函数绑定会自动进行
Yes.
但我的疑问是我听说建议使用普通
函数并将其绑定在构造函数中,而不是使用箭头函数
因为箭头函数在 Webpack 中创建新的对象/函数
每次组件渲染和重新渲染时都会调用bundle.js。
就像大家说的那样,这取决于你在哪里使用它们。
render() {
return (
<div>
<button onClick={() => this.aFunction()}>Click</button>
</div>
);
}
在这里,它将在每次渲染中重新创建。但如果您不需要向其传递任何参数,则可以通过引用来使用它。
render() {
return (
<div>
<button onClick={this.aFunction}>Click</button>
</div>
);
}
这与前一个一样。所以,如果你看到一个()
在您的渲染方法中,此函数会在每次渲染中重新创建。常规的还是箭头的,并不重要。如果您以某种方式调用它,那么您就是在重新创建它。这适用于渲染中的绑定,例如aFunction.bind(this)
. I see ()
there.
因此,通过引用使用函数可以避免此问题。现在,最大的问题是当我们需要一些论证时会发生什么?如果您使用箭头函数传递参数,请尝试更改您的逻辑。
但这真的那么重要吗?就像 @Eric Kim 所说,如果你确实需要的话,优化就是一个问题。这是一个一般性的建议,因为我从很多人那里听到过这个建议。但就我个人而言,如果函数会在每次渲染中重新创建,我会尽量避免使用它们。但同样,这完全是个人的。
怎样才能改变你的逻辑呢?您正在使用一个项目映射一个数组并创建
一个按钮。在此按钮中,您使用的函数将项目名称传递给函数。
{
items.map( item =>
<button onClick={() => this.aFunction(item.name)}>Click</button>
)
}
该函数将在每个项目的每次渲染中重新创建!所以,改变你的逻辑,创建一个单独的Item
组件并映射它。通过item
, aFunction
作为道具。然后通过该组件中的处理函数使用您的函数。
const Item = ( props ) => {
const handleClick = () => props.aFunction( props.item.name );
return (
<button onClick={handleClick}>Click</button>
);
}
在这里,您正在使用onClick
处理程序及其引用并调用您的实际函数。每次渲染中都不会重新创建任何函数。但是,缺点是您需要编写一个单独的组件和更多的代码。
大多数时候你都可以应用这个逻辑。也许会有一些你不能的例子,谁知道呢。所以决定权在你。
顺便说一下,@widged 在评论中给出的 Medium 帖子是关于这个问题的著名讨论。箭头函数真的比普通函数慢吗?是的。但多少钱呢?我想没那么多。此外,对于转译代码也是如此。将来当他们成为本地人时,他们将是更快的。
作为个人旁注。我一直在使用箭头函数,因为我喜欢它们。但前段时间在讨论中有人说
当我在类中看到箭头函数时,我想:“这个函数
正在此类之外使用/调用'。如果我看到一个普通的我
了解这个函数在类内部调用。
我真的很喜欢这种方法,现在如果我不需要在类之外调用我的函数,我将使用常规方法。