我一直在阅读一堆react
代码,并且看到一些我不理解的东西:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
我一直在阅读一堆react
代码,并且看到一些我不理解的东西:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
简洁 simple
它是一个函数,它返回另一个以简短方式编写的函数。
const handleChange = field => e => {
e.preventDefault()
// Do something here
}
// is equal to
function handleChange(field) {
return function(e) {
e.preventDefault()
// Do something here
}
}
人们为什么这样做 ❓
在需要编写可自定义的功能时遇到了什么?还是您必须编写一个具有固定参数(参数)的回调函数,但是您需要向该函数传递更多变量,但要避免使用全局变量?如果您的回答为“ 是 ”,那么这就是方法。
例如,我们有一个button
with onClick回调。而且我们需要传递id
给函数,但是onClick
只接受一个参数event
,因此不能像这样传递额外的参数:
const handleClick = (event, id) {
event.preventDefault()
// Dispatch some delete action by passing record id
}
不起作用!
因此,我们将创建一个函数,该函数将返回具有其自身变量范围的其他函数,而没有任何全局变量,因为全局变量是邪恶的。
下面的函数handleClick(props.id)}
将被调用并返回一个函数,它将id
在其作用域内!无论按下多少次,id都不会相互影响或改变,它们是完全隔离的。
const handleClick = id => event {
event.preventDefault()
// Dispatch some delete action by passing record id
}
const Confirm = props => (
<div>
<h1>Are you sure to delete?</h1>
<button onClick={handleClick(props.id)}>
Delete
</button>
</div
)
您的问题中的示例是curried function
使用第一个参数arrow function
并具有的a的示例implicit return
。
箭头函数按词法绑定此对象,即它们没有自己的this
参数,但从this
封闭范围获取值
与上面的代码等效
const handleChange = (field) {
return function(e) {
e.preventDefault();
/// Do something here
}.bind(this);
}.bind(this);
关于示例的另一件事要注意的是,将其定义handleChange
为const或函数。可能您将其用作类方法的一部分,并且使用了class fields syntax
因此,与其直接绑定外部函数,不如将其绑定到类构造函数中
class Something{
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(field) {
return function(e) {
e.preventDefault();
// do something
}
}
}
该示例中要注意的另一件事是隐式和显式返回之间的区别。
const abc = (field) => field * 2;
上面是隐式返回的示例,即。它以值字段作为参数,并返回结果field*2
,该结果明确指定要返回的函数
对于显式返回,您将显式告诉方法返回值
const abc = () => { return field*2; }
关于箭头功能要注意的另一件事是它们没有自己的功能,arguments
但也从父级范围继承了该功能。
例如,如果您仅定义一个箭头函数,例如
const handleChange = () => {
console.log(arguments) // would give an error on running since arguments in undefined
}
作为替代,箭头函数提供您可以使用的其余参数
const handleChange = (...args) => {
console.log(args);
}
一般提示,如果您对新的JS语法及其编译方式感到困惑,则可以检查babel。例如,将您的代码复制到babel中并选择es2015预设将给出类似的输出
handleChange = function handleChange(field) {
return function (e) {
e.preventDefault();
// Do something here
};
};
理解箭头函数的可用语法将使您了解在“链接”时它们所引入的行为,如您提供的示例中所示。
当编写不带大括号,带有或不带有多个参数的箭头函数时,将隐式返回构成函数主体的表达式。在您的示例中,该表达式是另一个箭头函数。
No arrow funcs Implicitly return `e=>{…}` Explicitly return `e=>{…}`
---------------------------------------------------------------------------------
function (field) { | field => e => { | field => {
return function (e) { | | return e => {
e.preventDefault() | e.preventDefault() | e.preventDefault()
} | | }
} | } | }
使用箭头语法编写匿名函数的另一个优点是将它们按词法绑定到定义它们的范围。从MDN上的“箭头功能”:
考虑到它是从reactjs应用程序中获取的,这在您的示例中特别相关。作为由@naomik指出的那样,在你做出反应经常访问组件的成员函数使用this
。例如:
Unbound Explicitly bound Implicitly bound
------------------------------------------------------------------------------
function (field) { | function (field) { | field => e => {
return function (e) { | return function (e) { |
this.setState(...) | this.setState(...) | this.setState(...)
} | }.bind(this) |
} | }.bind(this) | }
它可能并不完全相关,但是由于提到的问题react是用例(并且我一直碰到这个SO线程):双箭头功能的一个重要方面在这里没有明确提及。只有“第一个”箭头(函数)被命名(因此在运行时可以“区分”),随后的任何箭头都是匿名的,从React的角度来看,每个箭头都被视为“新”对象。
因此,双箭头功能将导致任何PureComponent始终重新渲染。
例
您有一个带有更改处理程序的父组件,如下所示:
并使用如下渲染:
{ tasks.map(task => <MyTask handleChange={this.handleChange(task)}/> }
然后在输入或单击上使用handleChange。这一切都有效并且看起来非常不错。但是,这意味着将导致父项重新呈现的任何更改(如完全不相关的状态更改)也将重新呈现所有MyTask,即使它们是PureComponents。
可以通过多种方式来缓解这种情况,例如传递“最外”箭头和您将使用的对象,或者编写自定义的shouldUpdate函数,或者回到基础知识,例如编写命名函数(并手动绑定此函数……)。