React 函数式组件与返回 React 元素的普通 JS 函数

IT技术 javascript reactjs react-jsx
2021-05-22 10:41:53

假设我定义了一个简单的 React 功能组件,如下所示:

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

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

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

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

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因为它允许我更轻松地使用函数式编程技术,例如柯里化,而且有时在调用时不必指定参数名称也很好。但是我这样做是否要付出某种代价?我最好坚持使用传统语法吗?

2个回答

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

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

但是,我理解您将它们称为函数的热情。为了组合,我也觉得它很有用。对于普通函数来说更是如此。
但是,同样,在未来,功能组件将有一个 state如果它发生了,我们可能会后悔我们的热情:)

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


IMO,无论差异如何,无论如何,优化仍在我们shouldComponentUpdate身上- 无论是. 可能不需要任何优化的组件重新渲染应该很便宜,反之亦然(如果它是纯计算,显然不是 DOM 操作)。

随意评论或更正,我会更新我的帖子。

我找到了一个解释,显然有人在官方 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.memo或 中React.lazy,这将中断。因此请谨慎使用此模式。