React函数组件中箭头函数和普通函数有什么区别?(不再使用类组件)

14

自从出现 React Hooks 之后,我决定放弃使用 React 类组件,现在只处理 hooks 和函数式组件。

简单的问题:

我理解在类体内使用箭头函数和普通函数的区别。箭头函数会自动绑定 (词法 this) 到我的类实例上,我不必在构造函数中绑定它。这很好。

但既然我不再处理类了,我想知道在函数式组件内部执行以下操作的区别是什么:

function App() {

  // REGULAR FUNCTION
  function handleClick1() {
    console.log('handleClick1 executed...');
  }

  // ARROW FUNCTION
  const handleClick2 = () => {
    console.log('handleClick2 executed...');
  }

  return(
    <React.Fragment>
      <div className={'div1'} onClick={handleClick1}>
        Div 1 - Click me
      </div>
      <div className={'div2'} onClick={handleClick2}>
        Div 2 - Click me
      </div>
    </React.Fragment>
  );
}

问题

两者都可以正常工作。

它们的性能有区别吗?应该偏爱一个而不是另一个吗?它们在每次渲染时都会被重新创建,对吗?


关于可能重复的说明

我真的不认为这是一个重复的问题。我知道有很多关于箭头函数和普通函数之间差异的问题,但我想从 React 函数组件的角度和 React 如何处理它来了解。我已经找过了,没有找到一篇相关的答案。


测试用代码片段

function App() {
  
  function handleClick1() {
    console.log('handleClick1 executed...');
  }
  
  const handleClick2 = () => {
    console.log('handleClick2 executed...');
  }
  
  return(
    <React.Fragment>
      <div className={'div1'} onClick={handleClick1}>
        Div 1 - Click me
      </div>
      <div className={'div2'} onClick={handleClick2}>
        Div 2 - Click me
      </div>
    </React.Fragment>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));
.div1 {
  border: 1px solid blue;
  cursor: pointer;
}

.div2 {
  border: 1px solid blue;
  cursor: pointer;
 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>


1
如果您没有使用this,那么函数内部的差异完全无关紧要。外部的区别在于函数声明被提升到作用域的顶部,将箭头函数分配给变量(var、const、let)则不会。var与const和let之间还有进一步的差异,但只有在引用尚未分配的内容时才会有影响。 - Jared Smith
1
无论你读过什么有关箭头函数、常规命名函数和使用变量声明的匿名函数的其他信息,在这里仍然适用。它们之间没有性能差异。而且在运行时甚至不可能检测到一个函数是否是箭头函数,所以React并不会以与常规函数不同的方式处理它们。 - Khauri
1
根据之前的评论,请参考这个这个 - Jared Smith
3
哎呀,我错了,我以为不能检测箭头函数。但是我非常怀疑React会这样做。主要是因为转译器的存在。 - Khauri
参见 https://dev59.com/V1oU5IYBdhLWcg3wnX1O#55784719 - Estus Flask
2个回答

6
除了你已经指出的区别(词法作用域),箭头函数(以及函数表达式)不会被提升,因此在定义之前不能调用。可以看看我的示例。在我看来,这不是一个问题,因为依赖提升的代码更难理解。
React 真的不关心你使用哪个(也无法检测它)。

const A = () => {
  const name = getName();
  
  function getName() {
    return 'praffn';
  }
  
  // Will not work
  // const getName = () => 'praffn';
  
  return <p>Hi, {name}</p>;
}

ReactDOM.render(<A/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>


2
就我个人而言,实际上并没有发现函数提升在实践中有太大的问题(不像var提升),而且我认为在代码中使用function关键字可以使其比几乎所有都以const开头的情况更具可读性。(我猜Facebook在使用function的例子时可能也有类似的原因。)但正如菲利普已经指出的那样,这是一种风格上的偏好——任何一种方式都很好。 - Matt Browne
2
@MattBrowne,我实际上更喜欢使用“function”关键字 - 对我来说它更易读。我通常只在一行代码和高阶函数中使用箭头函数。但是,尽可能避免依赖变量提升。 - Phillip
@MattBrowne 我认为 function 关键字也使代码更易读。而且我几乎从不使用提升“特性”。 - cbdeveloper

5

既然您没有访问this上下文,那么两者的行为都将相同

为了更好地理解,您可以查看Babel是如何转换成ECMA的:

 const handleClick2 = () => {
    console.log('handleClick2 executed...');
    this.x=3
 }

将被转译为:

"use strict";

var _this = void 0;

var handleClick2 = function handleClick2() {
  console.log('handleClick2 executed...');
  _this.x = 3;
};

链接到 Babel 记事本


1
在箭头函数或函数声明中访问this将不会有任何区别,因为this将等于undefined。这是因为React组件是在ES6模块中编写的,自动运行在严格模式下 - Ani Naslyan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接