何时使用基于ES6类的React组件和功能性ES6 React组件?


211

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

我的问题是,什么时候应该使用哪个?为什么?一个人相对于另一个人的利益/取舍是什么?


ES6课程:

import React, { Component } from 'react';

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

功能性:

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

我正在考虑什么时候只要该组件没有状态要操作就可以了,是吗?

我在猜测是否使用任何生命周期方法,最好是使用基于类的组件。


7
看来您已经知道答案了。
菲利克斯·克林

2
如果您只有使用render方法的组件,则可以将其转换为功能形式。如果您需要除无状态渲染功能之外的其他功能,请使用类
刚无聊的时候16-3-20

2
为了更加简洁,请尝试以下操作:const MyComponent = (props) => <div>...</div>
Viliam Simko

1
如果可以避免,我从不使用功能。因为我不可避免地最终需要重构为基于类的方式。然后,之后通常需要将其重构为功能。
keithjgrant

2020年,正确的方法是尽可能使用功能组件,因为它们支持钩子,并且钩子(在性能方面和体系结构上)优于替代组件。
polkovnikov.ph

Answers:


161

你有正确的想法。如果您的组件只做一些道具和渲染,那么功能就可以了。您可以将它们视为纯函数,因为在给定相同的道具的情况下,它们将始终呈现并表现相同的行为。而且,他们不关心生命周期方法或具有自己的内部状态。

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

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

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


编辑:以上大部分是正确的,直到引入React Hooks。

  • componentDidUpdate可以使用复制useEffect(fn),其中fn在重新渲染时运行的功能。

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

  • state可以复制为useState(),其返回值可以解构为状态的引用以及可以设置状态的函数(即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

关于何时在功能组件上使用类的建议,Facebook正式建议尽可能使用功能组件。顺便说一句,我听到很多人讨论出于性能原因不使用功能组件,特别是

“事件处理功能在功能组件中按渲染重新定义”

虽然正确,但是请考虑您的组件是否真的以值得关注的速度或体积进行渲染。

如果是这样,则可以防止使用useCallbackuseMemo挂钩重新定义功能。但是,请记住,这可能会使您的代码(微观上)的性能降低

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


不保持状态但紧密耦合到组件的功能怎么样,例如确定渲染的一些动态属性。
丹尼斯,

这是关于两种类型的组件之间的差异的最好的文章阵营:code.tutsplus.com/tutorials/...
阿里安阿科斯塔

5
从React 16.8开始,您可以通过useState钩子在功能组件中使用状态。
格雷格

从React 16.8开始,您几乎可以在功能组件中进行所有操作,并且最终所有的效果都可以模块化,而对性能的影响很小。
polkovnikov.ph

1
您在哪里找到信息Facebook officially recommends using functional components wherever possible
johannchopin

40

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

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

更新

现在有一个称为React的类PureComponent,您可以扩展(而不是Component)来实现它自己的方法shouldComponentUpdate,该方法可以为您比较浅道具。阅读更多


43
Always try to use stateless functions (functional components) whenever possible.我读过十个人说。他们仍然没有给出任何解释。
Rotareti '16

25
In an ideal world, most of your components would be stateless functions because in the future we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations. This is the recommended pattern, when possible.更多信息:facebook.github.io/react/docs/...
迪奥戈·卡多佐

2
@rotareti我不知道您是否感到自己的问题得到了回答,但是纯函数更容易理解,测试和维护。给定相同的参数,它们始终呈现相同的事物。生命周期事件发生时保持状态并更改的组件更难理解。并不是说有时不需要它们,但是我希望很明显,如果不需要它们的优点,那么它们所做的就是添加不需要的样板和开销而没有任何好处。
door_number_three

如果您有自己的事件处理程序定义,则还需要创建一个Component类。这样,您可以将这些事件处理程序预绑定到构造函数中的组件,而不用在每个渲染器上创建一个新的新函数。请注意,如果您所有的事件处理程序都来自道具,则不需要这样做。
Dobes Vandermeer

请注意,引用的Facebook建议不再存在(请参阅上面的评论)。
加勒特

34

2019年3月更新

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

2019年2月更新:

随着React钩子的引入团队似乎希望我们尽可能使用功能组件(更好地遵循JavaScript的功能性质)。

他们的动力:

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

带有钩子的功能组件几乎可以执行类组件可以执行的所有操作,而无需上面提到的任何缺点。

我建议您尽快使用它们。

原始答案

功能组件没有比基于类的组件更轻巧,“它们的表现与类完全相同”。- https://github.com/facebook/react/issues/5677#issuecomment-241190513

上面的链接有些过时了,但是React 16.7.0的文档说功能和类组件:

“从React的观点来看是等效的。” - https://reactjs.org/docs/components-and-props.html#stateless-functions

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

将来(引用上面的链接)“我们[反应]可能会添加此类优化。”

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

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

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

这完全取决于您。如果您希望减少样板,请继续使用。如果您喜欢函数式编程并且不喜欢类,请使用函数式。如果要在代码库中的所有组件之间保持一致性,请使用类。如果您在需要诸如的东西时已经厌倦了从功能性组件重构为基于类的组件state,请使用类。


1
我认为使每个组件都扩展React.Component可以使代码更具可读性,特别是对于新手。每次看到一个组件以相同的方式创建时,这是很好的。就像@Galupuf所说的那样,简单的组件只有一种称为“ render()”的方法。使所有内容都扩展React.Component也很好,因为当您要开始绑定“ this”,具有状态等时,您不必重构所有内容,只需添加所需的内容即可。
jeffski13年

10

从React 16.8开始,术语无状态功能组件具有误导性,应避免使用它们,因为它们不再不再是无状态的(React.SFC不推荐使用Dan Abramov on React.SFC),它们可以具有状态,可以具有钩子(充当钩子)生命周期方法),它们或多或少与类组件重叠

基于类的组件

功能组件:

为什么我更喜欢功能组件

  • 反应提供useEffect挂钩,是结合了非常清晰和简洁的方式componentDidMountcomponentDidUpdate以及componentWillUnmount生命周期方法
  • 使用钩子,您可以提取可以在组件之间轻松共享测试的逻辑
  • 减少范围界定上的混乱

反应动机为何使用挂钩(即功能组件)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.