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

我的问题是什么时候应该使用哪个,为什么?其中一种与另一种相比有什么好处/权衡?


ES6签署:

import React, { Component } from 'react';

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

功能:

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

我认为函数是指没有状态可以被那个组件操纵的情况,但真的是这样吗?

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


只要可能,总是尝试使用无状态函数(功能组件)。在某些情况下,你需要使用一个常规的React类:

组件需要维护状态 组件重新渲染过多,您需要通过shouldComponentUpdate来控制它 您需要一个容器组件

更新

现在有一个名为PureComponent的React类,你可以扩展(而不是Component),它实现了自己的shouldComponentUpdate,为你处理浅道具比较。阅读更多

新的回答:在React Hooks出现之前,以下大部分都是正确的。

componentDidUpdate can be replicated with useEffect(fn), where fn is the function to run upon rerendering. componentDidMount methods can be replicated with useEffect(fn, []), where fn is the function to run upon rerendering, and [] is an array of objects for which the component will rerender, if and only if at least one has changed value since the previous render. As there are none, useEffect() runs once, on first mount. state can be replicated with useState(), whose return value can be destructured to a reference of the state and a function that can set the state (i.e., const [state, setState] = useState(initState)). An example might explain this more clearly:

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

说句题外话,我听过很多人因为性能原因而讨论不使用功能组件,特别是这个原因

事件处理函数在功能组件的每次渲染中被重新定义

尽管如此,请考虑你的组件是否真的以这样的速度或体积渲染,这将是值得关注的。

如果是,可以使用useCallback和useMemo钩子防止重新定义函数。但是,请记住,这可能会使您的代码(在微观上)性能变差。

但说实话,我从未听说过重新定义函数会成为React应用程序的瓶颈。过早的优化是万恶之源——当它成为一个问题时,要担心这一点。


老回答:你的想法是对的。如果你的组件只包含一些道具和渲染,那就使用功能性组件。您可以将它们看作纯函数,因为给定相同的道具,它们将始终呈现和表现相同。此外,它们不关心生命周期方法或拥有自己的内部状态。

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

如果你的组件需要更多的功能,比如保持状态,请使用类。

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

2023年1月更新

TLDR;函数是创建组件的最佳方式。反应。组件是一个遗留API。

“我们建议将组件定义为函数而不是类。”

React仍然支持类组件,但我们不建议在新代码中使用它们。”

https://beta.reactjs.org/reference/react/Component

2019年3月更新

在我最初回答的基础上:

React函数和React函数之间有什么根本区别吗 还上课吗?当然,在心智模型中。

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

2019年2月更新:

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

他们的动机:

很难在组件之间重用有状态逻辑。 复杂的组件变得难以理解。 课程让人和机器都感到困惑。

带有钩子的功能组件几乎可以做类组件可以做的所有事情,没有上面提到的任何缺点。

我建议你尽快使用它们。

原来的答案

功能组件并不比基于类的组件更轻量级,“它们完全像类一样执行。”——https://github.com/facebook/react/issues/5677 # issuecomment - 241190513

上面的链接有点过时,但React 16.7.0的文档说 函数组件和类组件:

从React的角度来看是等价的吗

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

功能组件和只实现呈现方法的类组件本质上没有区别,只是语法不同。

今后(引用上述链接):

我们React可能会添加这样的优化

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

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

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

这完全取决于你。如果你想要更少的样板文件,那就使用功能。如果你喜欢函数式编程,不喜欢类,那就选择函数式编程。如果您希望代码库中的所有组件保持一致,请使用类。如果您厌倦了在需要状态之类的东西时将函数组件重构为基于类的组件,那么就使用类。

在React 17中,术语无状态功能组件是误导性的,应该避免使用。SFC已弃用,Dan Abramov在React.SFC上),它们可以有状态,也可以有钩子(充当生命周期方法),它们或多或少与类组件重叠

基于类的组件

状态 生命周期方法 用React记忆。PureComponent

功能组件:

state (useState, useReducer钩子) 生命周期方法(通过useEffect, useLayoutEffect钩子) 通过备忘录HOC进行记忆

为什么我更喜欢功能性组件

React提供了useEffect钩子,这是一种非常清晰和简洁的方式来组合componentDidMount, componentDidUpdate和componentWillUnmount生命周期方法 使用钩子,您可以提取可以在组件之间轻松共享和可测试的逻辑 减少对范围的混淆

React动机为什么使用钩子(即功能组件)。

使用functional表单更简单,因为可以重用表单输入字段,还可以使用React显示条件将它们分开。

类是一个不能分解或重用的大组件。它们更适合于功能丰富的组件,比如在弹出式模块中执行算法的组件。

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

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

我在生产中使用了大量的功能组件。我只在“错误边界”中使用过一次类组件,因为在功能组件中没有可选的“错误边界”。

我只使用了一次“类组件”。

基于类的组件提供了一种更加结构化和有组织的方式来定义和实现组件,并且它们提供了额外的特性和功能,例如使用本地状态和生命周期方法的能力。这可以使它们成为创建需要大量逻辑和功能的复杂组件的好选择。

另一方面,功能组件更简单,更容易使用,而且它们的性能更高,因为它们更轻量级。它们也更容易测试和调试,因为它们是纯函数,没有副作用。这使得它们成为创建不需要大量逻辑或状态管理的简单组件的好选择。