何时使用基于 ES6 class 的 React 组件与功能性 ES6 React 组件?

When to use ES6 class based React components vs. functional ES6 React components?

在花了一些时间学习 React 之后,我了解了创建组件的两种主要范式之间的区别。

我的问题是什么时候应该使用哪一个?为什么?一个比另一个的 benefits/tradeoffs 是多少?


ES6 classes:

import React, { Component } from 'react';

export class MyComponent extends Component {
  render() {
    return (
      <div></div>
    );
  }
}

功能性:

const MyComponent = (props) => {
    return (
      <div></div>
    );
}

我认为只要该组件没有可操作的状态就可以正常工作,但真的是这样吗?

我猜如果我使用任何生命周期方法,最好使用基于 class 的组件。

尽可能始终尝试使用无状态功能(功能组件)。在某些情况下,您需要使用常规 React class:

  • 组件需要保持状态
  • 该组件重新渲染过多,您需要通过 shouldComponentUpdate
  • 进行控制
  • 你需要一个container component

更新

现在有一个名为 PureComponent 的 React class,您可以扩展它(而不是 Component),它实现了自己的 shouldComponentUpdate,负责浅层道具比较你。 Read more

新答案:在引入 React Hooks 之前,以下大部分内容都是正确的。

  • componentDidUpdate 可以用 useEffect(fn) 复制,其中 fn 是重新渲染时 运行 的函数。

  • componentDidMount 方法可以用 useEffect(fn, []) 复制,其中 fn 是重新渲染时 运行 的函数,[]是一个对象数组,组件将为其重新渲染,当且仅当自上次渲染以来至少有一个值已更改。由于有 none、useEffect() 运行 一次,在第一次安装时。

  • state 可以用 useState() 复制,其 return 值可以解构为状态的引用和可以设置状态的函数(即 const [state, setState] = useState(initState))。一个例子可能会更清楚地解释这一点:

const Counter = () => {
  const [count, setCount] = useState(0)

  const increment = () => { 
    setCount(count + 1);
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+</button>
    </div>
  )
}

default export Counter

顺便说一句,我听到很多人讨论出于性能原因不使用功能组件,特别是

"Event handling functions are redefined per render in functional components"

尽管如此,但请考虑您的组件是否真的以值得关注的速度或体积呈现。

如果是,您可以使用 useCallbackuseMemo 挂钩阻止重新定义函数。但是,请记住,这可能会使您的代码(微观上)worse in performance.

但老实说,我从未听说过重新定义函数是 React 应用程序的瓶颈。过早的优化是万恶之源 - 出现问题时要担心这一点。


旧答案:你的想法是对的。如果你的组件除了接受一些道具和渲染之外没有做更多的事情,那就选择功能性的。您可以将它们视为纯函数,因为在给定相同的 props 的情况下,它们将始终呈现并表现相同。此外,他们不关心生命周期方法或有自己的内部状态。

因为它们是轻量级的,所以将这些简单的组件编写为功能组件是非常标准的。

如果您的组件需要更多功能,例如保持状态,请改用 类。

更多信息:https://facebook.github.io/react/docs/reusable-components.html#es6-classes

2019 年 3 月更新

基于我原来的回答中所述:

Are there any fundamental differences between React functions and classes at all? Of course, there are — in the mental model.

https://overreacted.io/how-are-function-components-different-from-classes/

2019 年 2 月更新:

随着 React hooks 的引入,React 团队似乎希望我们尽可能使用函数式组件(这更好地遵循了 JavaScript 的函数式本质)。

他们的动机:

1.) It’s hard to reuse stateful logic between components
2.) Complex components become hard to understand
3.) Classes confuse both people and machines

带钩子的功能组件可以做 almost class 组件可以做的一切,没有上面提到的任何缺点。

我建议您尽快使用它们。

原答案

函数式组件并不比基于 class 的组件更轻量,“它们的性能与 classes 完全一样。” - https://github.com/facebook/react/issues/5677#issuecomment-241190513

上面的 link 有点过时,但是 React 16.7.0 的文档说 该功能和 class 组件:

are equivalent from React’s point of view

https://reactjs.org/docs/components-and-props.html#stateless-functions

除了语法之外,功能组件和 class 组件之间基本上没有区别,只是实现了 render 方法。

以后(引用上面link):

we [React] might add such optimizations

如果您试图通过消除不必要的渲染来提高性能,这两种方法都可以提供支持。 memo 用于功能组件,PureComponent 用于 classes.

-https://reactjs.org/docs/react-api.html#reactmemo

-https://reactjs.org/docs/react-api.html#reactpurecomponent

这真的取决于你。如果您想要更少的样板文件,请使用功能。如果你喜欢函数式编程但不喜欢 classes,那就去函数式吧。如果您想要代码库中所有组件之间的一致性,请使用 classes。如果你厌倦了从功能组件重构到基于 class 的组件,而你需要类似 state 的东西,请使用 classes.

从 React 17 开始,无状态功能组件一词具有误导性,应避免使用 (React.SFC deprecated, Dan Abramov on React.SFC),它们可以有状态,也可以有钩子(充当生命周期方法),它们或多或少与 class 个组件

重叠

Class 基于组件

功能组件:

为什么我更喜欢功能组件

  • React 提供了 useEffect 钩子,这是一种非常清晰简洁的方式来组合 componentDidMountcomponentDidUpdatecomponentWillUnmount 生命周期方法
  • 使用钩子,您可以提取可以轻松地跨组件共享并且可测试
  • 的逻辑
  • 减少对范围的混淆

反应 motivation 为什么使用钩子(即功能组件)。

使用函数式表单更容易,因为您可以重复使用表单输入字段,并且可以使用 React 显示条件将它们分开。

类 是一个无法分解或重复使用的大组件。它们更适合 function-heavy 组件,例如在 pop-up 模块或其他东西中执行算法的组件。

最佳实践是功能组件的可重用性,然后使用小的功能组件来 assemble 完成部分,例如-将输入字段导入到 React 表单的文件中。

另一个最佳做法是在执行此操作的过程中不要嵌套组件。

我已经将功能组件用于生产中使用频繁的应用程序。我只有一次使用 class 组件作为“错误边界”,因为在功能组件中没有替代的“错误边界”。

我只用了一次“class 组件”。