【问题标题】:When to use ES6 class based React components vs. functional ES6 React components?何时使用基于 ES6 类的 React 组件与功能性 ES6 React 组件?
【发布时间】:2021-08-11 13:04:13
【问题描述】:

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

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


ES6 类:

import React, { Component } from 'react';

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

功能:

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

只要该组件没有状态可操作,我就会认为是函数式的,但是是这样吗?

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

【问题讨论】:

  • 看来你已经知道答案了。
  • 如果你有一个只有render方法的组件,你可以把它变成函数形式。如果您需要的不仅仅是无状态渲染功能,请使用类
  • 为了更简洁,试试这个:const MyComponent = (props) =&gt; &lt;div&gt;...&lt;/div&gt;
  • 如果可以避免,我从不使用功能性。因为我不可避免地最终需要重构为基于类的方式。然后经常需要在那之后重构回功能。
  • 在 2020 年,正确的做法是尽可能使用功能组件,因为它们支持钩子,并且钩子(在性能方面和架构上)比替代品更好。

标签: javascript reactjs ecmascript-6 redux


【解决方案1】:

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

因为它们是轻量级的,所以将这些简单的组件写成函数式组件是相当标准的。

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

更多信息: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

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

“在功能组件中每次渲染都重新定义事件处理函数”

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

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

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

【讨论】:

  • 那些不保持状态但与组件紧密耦合的功能呢?确定渲染的一些动态属性。
  • 从 React 16.8 开始,您可以通过 useState 钩子在功能组件中使用状态。
  • 你在哪里找到Facebook officially recommends using functional components wherever possible的信息?
  • 我也很好奇Facebook officially recommends using functional components wherever possible
  • 似乎FB的建议随着时间的推移而改变:在2016-June,他们推荐功能组件,在2016-Oct,当你不需要状态时,他们推荐功能组件,当你需要时使用ES6类,在@ 987654325@,他们的推荐被完全删除了。
【解决方案2】:

从 React 17 开始,无状态功能组件这一术语具有误导性,应该避免使用(React.SFC deprecatedDan Abramov on React.SFC),它们可以有状态,也可以有钩子(充当生命周期方法),它们与类组件或多或少重叠

基于类的组件

功能组件:

为什么我更喜欢功能组件

  • React 提供了 useEffect 钩子,这是一种非常简洁明了的方式来组合 componentDidMountcomponentDidUpdatecomponentWillUnmount 生命周期方法
  • 使用钩子,您可以提取可以在组件之间轻松共享可测试的逻辑
  • 关于范围的混淆更少

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

【讨论】:

    【解决方案3】:

    2019 年 3 月更新

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

    “React 函数和类之间有什么根本区别吗?当然有——在心智模型中。”

    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 类组件可以做的所有事情,而没有上面提到的任何缺点。

    我建议您尽快使用它们。

    原答案

    功能组件并不比基于类的组件更轻量级,“它们完全像类一样执行。” - 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

    这真的取决于你。如果您想要更少的样板,请使用功能。如果您喜欢函数式编程并且不喜欢类,请使用函数式编程。如果您希望代码库中所有组件之间保持一致,请使用类。如果您厌倦了在需要 state 之类的东西时将基于函数的组件重构为基于类的组件,请使用类。

    【讨论】:

    • 我认为让每个组件都扩展 React.Component 会使代码更具可读性,尤其是对于新人而言。当您看到每次都以相同的方式创建组件时,这很好。就像@Galupuf 说的,简单的组件只有一种叫做“render()”的方法。让所有东西都扩展 React.Component 也很好,因为当你想开始绑定“this”、拥有状态等时,你不必重构所有东西,你只需添加你需要的东西。
    • 第 2 点和第 3 点既多余又毫无根据。
    • @jeffski13 所以你赞成基于类的反应组件?还是功能组件?
    【解决方案4】:

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

    类是一个不能分解或重用的重要组件。它们更适合功能繁重的组件,例如在弹出模块中执行算法的组件或其他东西。

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

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

    【讨论】:

    • “类不能重用”是什么意思?
    • 类是一个不能分解或重用的大组件?如果你把一个组件分解成多个类组件怎么办?
    • 我们一直在分解课程。所有的设计模式都是关于分解类。
    【解决方案5】:

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

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

    更新

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

    【讨论】:

    • Always try to use stateless functions (functional components) whenever possible. 我读过十个人这么说。仍然没有人解释原因。
    • 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/…
    • @rotareti 我不知道你是否觉得你的问题得到了解答,但纯函数更易于理解、测试和维护。给定相同的参数,它们总是渲染相同的东西。在生命周期事件发生时保持状态和更改的组件更难理解。并不是说有时不需要它们,但我希望很清楚,如果不需要它们的优点,它们所做的只是添加不需要的样板和开销,而没有任何好处。
    • 如果您有自己的事件处理程序定义,您还需要创建一个组件类。这样,您可以将这些事件处理程序预先绑定到构造函数中的组件,而不是在每次渲染时创建一个全新的函数。请注意,如果您的所有事件处理程序都来自 props,则不需要这样做。
    • 请注意,引用的 Facebook 推荐不再存在(参见上面的 my comment)。
    猜你喜欢
    • 2017-05-27
    • 2015-11-20
    • 2019-11-27
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多