我经常看到使用箭头函数语法定义的函数式React组件的示例:
const foo = () => (...);
export default foo;
与更传统的函数声明语法不同:
export default function foo() {
return ...;
}
前者是否比后者更优的原因是什么?
我经常看到使用箭头函数语法定义的函数式React组件的示例:
const foo = () => (...);
export default foo;
与更传统的函数声明语法不同:
export default function foo() {
return ...;
}
前者是否比后者更优的原因是什么?
实际上它们之间没有区别,我在CodeSandBox上创建了一个小项目并创建了两个简单组件,其中一个是使用箭头函数创建的Arrow
组件:
import React from 'react';
const MyArrowComponent = () => (
<main>
<h2>Arrow</h2>
</main>
);
export default MyArrowComponent;
另一种方法是使用函数声明创建 Declaration
组件:
import React from "react";
function MyFunctionComponent() {
return (
<main>
<h2>Declaration</h2>
</main>
);
}
export default MyFunctionComponent;
yarn build
命令,得到了以下的捆绑包:(window.webpackJsonp = window.webpackJsonp || []).push([[0], {
14: function (e, n, t) {
"use strict";
t.r(n);
var a = t(0), r = t.n(a), l = t(2),
c = t.n(l), u = t(3), i = t(4), o = t(6), m = t(5), E = t(7);
var p = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Declaration"))
}, s = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Arrow"))
}, d = function (e) {
function n() {
return (
Object(u.a)(this, n),
Object(o.a)(this, Object(m.a)(n).apply(this, arguments))
}
return Object(E.a)(n, e), Object(i.a)(n, [{
key: "render", value: function () {
return r.a.createElement(
'div',
null,
r.a.createElement('div', null, 'Hi'),
r.a.createElement(p, null),
r.a.createElement(s, null)
);
}
}]), n
}(r.a.Component);
c.a.render(r.a.createElement(d, null), document.getElementById("root"))
}, 8: function (e, n, t) {
e.exports = t(14)
}
}, [[8, 1, 2]]]);
请注意Arrow
和Declaration
组件的定义:
var p = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Declaration"))
}, s = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Arrow"))
}
这两者的定义方式是相同的,因此它们之间没有区别,完全取决于开发人员对代码可读性和清晰性的态度,根据我们团队使用的ESLint 5.x,我们选择使用箭头函数来定义功能组件。
我认为这是一个带有主观色彩的选择。至少有几个原因让我(个人而言)认为在纯函数组件中使用箭头函数是一种相当糟糕的实践。以下是这些原因:
语法滥用。我们定义函数组件时不需要将其上下文预先绑定到特定范围。该上下文(this
)在模块命名空间中将始终为undefined
。箭头函数的使用在这里由纯美学理由,如简洁性所决定。但是,箭头函数作为语言特性首先存在的目的并不是“酷炫”和简洁。
错误堆栈跟踪。在箭头函数中抛出的异常将不太具描述性,因为箭头函数本质上是匿名的。这可能不是巨大的问题,因为React项目很可能配置了适当的源映射支持,但如果使用命名函数,则堆栈跟踪会更清晰。 如评论中所述,这实际上不是函数组件的问题,因为名称基本上将是变量的名称。
日志记录不太方便。考虑这种非常典型的纯函数组件样式:
const Header = ({ name, branding }) => (
<header>
...
</header>
)
在上面的函数中,无法快速插入debugger
语句或console.log
。您将不得不将其暂时转换为以下内容
const Header = function ({ name, branding }) {
console.log(name)
return (
<header>
...
</header>
)
}
对于较大的纯函数组件来说,这可能会非常烦人。
尽管如此,这是许多团队非常流行的选择,也是ESLint默认首选,所以如果您没有看到问题,那么它可能没问题。
console.log(),
或 eval('debugger')
。请注意,React函数组件已经为此提供了 (...)
。此外,这不是关于常规函数与箭头函数的区别,而是关于隐式返回与显式返回。但调试的重要之处在于,在常规函数中可以使用 arguments
(但箭头函数在ES5目标中也会有它)。 - Estus Flaskconst Header = ({ name, branding }) => {
console.log(name);
return (
...
);
}
- wmp224name
以进行检查? - dfsq函数声明和箭头函数在本质上是不同的,但在您的问题范围内,这基本上是一种代码风格偏好。就个人而言,我更喜欢函数声明,因为我觉得它更容易看出代码行的含义。
如果您将使用箭头函数或函数声明,请尝试从上下文中考虑哪种方式更有意义,从而使代码更干净,更易于阅读。清晰易读的代码不仅关乎编写的代码量,还关乎代码表达的内容。
例如,我倾向于在回调时使用箭头函数,如:[].map(() => {})
.map/.filter/.reduce
,编写命名函数会引入不一致性。这是一个虽然薄弱但仍有道理的论点。 - Walter Monecke其他答案中未提及的几点:
匿名
,使调试变得更加困难。这些匿名组件也在性能火焰树等开发工具中普遍存在。函数式组件在dev tools中显示其名称。export default
。当您想添加/删除default
关键字时,这也会使其更容易。export default async function MyComponent() {
...
}
作用域安全:一旦始终使用箭头函数,将保证所有函数使用相同的thisObject作为根对象。如果将单个标准函数回调与大量箭头函数混合使用,则有可能会破坏作用域。
紧凑性:箭头函数易于阅读和编写。
清晰性:当几乎所有函数都是箭头函数时,任何常规函数立即显露出来以定义作用域。开发人员可以始终查找下一个更高的函数语句,以查看此对象。
欲了解更多细节,请参阅以下问题
this
绑定是无关紧要的。 - Jimmy Breck-McKyefunction
可以轻松识别声明是函数还是变量,而无需视觉扫描向右。我非常讨厌阅读文件时,从左到右排列的const
,因为需要扫描右侧以确定它是函数还是变量。使用function
关键字将使得代码在从上到下扫描时更容易,而无需从左到右扫描。 - Charles Chenexport const Component = () => {…};
实际上比export function Component() {…}
更长。 - Bergi
function
。 - rodrigocfd