【问题标题】:React functional component vs. plain-old JS function that returns React elementReact 函数式组件与返回 React 元素的普通 JS 函数
【发布时间】:2017-05-31 15:47:03
【问题描述】:

假设我这样定义一个简单的 React 函数式组件:

const Greeter1 = ({name}) => <h1>Hello {name}</h1>;

我还可以定义一个等效的普通 JS 函数,它返回一个 React 元素,如下所示:

const Greeter2 = name => <h1>Hello {name}</h1>;

“React”版本当然也只是一个普通的 JS 函数,接收一个 JS 对象而不是一个字符串。我们可以在纯 JS 中使用这些函数中的任何一个来获取给定名称的 greeter 元素,只是调用者语法略有不同:

const greeterElement1 = Greeter1({ name: "Bob" });
const greeterElement2 = Greeter2("Bob");

不过,在 React 表达式中,我们可以通过几种不同的方式调用这些函数:

const someReact1 = <div>{ Greeter2("Bob") }</div>;
const someReact2 = <div>{ Greeter1({ name: "Bob" }) }</div>;
const someReact3 = <div><Greeter1 name="Bob" /></div>;

我的问题:除了语法美学之外,这些调用风格之间是否有任何有效的区别?我假设someReact1someReact2 几乎相同,但我不确定someReact3。使用 React 组件语法会改变 React 处理事物的方式吗?它是否以任何方式影响行为或表现?还是仅仅是语法糖?

当在虚拟 DOM 树上做一个 diff 时,如果它的属性在渲染之间没有改变,React 是否会放弃在功能组件内进行比较?如果是这样,我假设在someReact1 中直接调用函数时会丢失优化是否正确?

我想知道 b/c 在某些情况下我实际上更喜欢 someReact1 的风格,因为它使我可以更轻松地使用函数式编程技术,例如柯里化,而且有时在调用时不必指定参数名称也很好。但我这样做是不是要付出某种代价?我最好还是坚持传统的语法?

【问题讨论】:

  • 我自己也在思考这个问题。到目前为止,我发现&lt;Greeter1 /&gt; 基本上编译为React.createElement(Greeter1),而像{Greeter1()} 这样嵌入在JSX 中的函数调用在编译时并没有真正改变。这就是我所得到的,但我认为这才是真正的区别。这对我还没有弄清楚的事情有什么影响。它们在 HTML 树中呈现相同。不确定它们在 React 的虚拟 DOM 中是什么样子的。
  • 由于虚拟 DOM 的差异,事物的行为方式也可能出现意想不到的差异。这给我今天造成了一个破坏布局的 CSS 错误:stackoverflow.com/questions/67242769/…

标签: javascript reactjs react-jsx


【解决方案1】:

自 React 16 以来,组件函数比类组件是 (a bit?) faster。不确定之前的版本是否如此。

将组件函数作为函数调用是much faster,而不是通过JSX/React.createElement调用它。 但是,在大多数情况下,这不应该影响我们编写代码的方式,因为 JSX 非常易读。为了填补这个空白,我们应该使用@babel/plugin-transform-react-inline-elements

但是,我理解您将它们称为函数的热情。为了构图,我也觉得它很有用。对于普通函数来说更是如此。
但是,同样,在未来,functional components are going to have a state。如果发生这种情况,我们可能会后悔我们的热情:)

普通函数seem to be faster 比组件函数。但是,我还没有深入研究这个话题。例如,我不确定它是否适用于react-hot-reload。或者,它在性能和可能的优化方面的优缺点。


IMO,无论有什么不同,无论如何,优化仍然在我们身上 - 无论是shouldComponentUpdate、备忘录还是密钥。可能不需要任何优化的组件应该重新渲染便宜,反之亦然(如果它是纯计算,显然不是 DOM 操作)。

欢迎评论或指正,我会更新我的帖子。

【讨论】:

    【解决方案2】:

    我找到了一个解释,显然有人在官方 React 存储库的 Github 问题中提出了类似的问题。这是问题https://github.com/facebook/react/issues/16796 的链接和线程的摘录,由贡献者提供的答案:

    我想了解的是:真的有必要打电话吗 再次 React.createElement,因为它已经在返回值中 组件?那和之间有什么有效的区别吗 像这样直接调用函数组件?

    正如@hamlim 所提到的,有效的区别在于,如果组件比返回另一个 React 元素的纯函数更复杂,那么简单地将组件作为函数调用是行不通的。 React 需要从 React.createElement 返回的元素来处理这些功能。

    HelloMessage 示例中,从技术上讲,您可以将其作为函数调用,这相当于:

    ReactDOM.render(
      <div>Hello Taylor</div>,
      document.getElementById("hello-example")
    );
    

    这只是内联HelloMessage 的结果,它将在浏览器中呈现相同的 UI。这就是你通过调用HelloMessage 作为一个函数所做的事情。在内部,这与 React 不同,因为没有安装组件,但实际上在这个简单的示例中行为是相同的。

    对于ParentComponent 示例,应用相同的约束。如果ChildComponent 组件只是没有状态或效果的简单组件,您可以将它们称为函数,这与将其内容内联到ParentComponent 的结果相同。在相同的情况下,这可能是您想要的,但通常不是。如果有人将状态或效果添加到 ChildComponents 之一,或将其包装在 React.memoReact.lazy 中,这将中断。因此请谨慎使用此模式。

    【讨论】:

      猜你喜欢
      • 2017-10-09
      • 2012-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-05
      • 2021-02-22
      相关资源
      最近更新 更多