【问题标题】:In React, can I define a functional component within the body of another functional component?在 React 中,我可以在另一个功能组件的主体中定义一个功能组件吗?
【发布时间】:2020-09-14 18:05:14
【问题描述】:

我开始看到我的一些团队编写了以下代码,这让我怀疑我们是否以正确的方式做事,因为我以前从未见过这样写。

import * as React from "react";
import "./styles.css";

function UsualExample() {
  return <h1>This is the standard example…</h1>
}

export default function App() {
  const CustomComponent = (): JSX.Element => <h1>But can I do this?</h1>
  return (
    <div className="App">
      <UsualExample />
      <CustomComponent />
    </div>
  );
}

它似乎渲染得很好,我看不到任何直接的不利影响,但是我们不应该在另一个组件中定义 CustomComponent 功能组件有什么根本原因吗?

代码沙盒示例: https://codesandbox.io/s/dreamy-mestorf-6lvtd?file=/src/App.tsx:0-342

【问题讨论】:

  • 是的,你可以!不要永远这样做,这不合逻辑且毫无意义。

标签: javascript reactjs jsx react-functional-component


【解决方案1】:

这不是一个好主意。每次App 重新渲染时,它都会为 CustomComponent 做出全新的定义。它具有相同的功能,但由于它是不同的引用,因此 react 需要卸载旧的并重新安装新的。因此,您将强制 react 在每次渲染上做额外的工作,并且您还将重置 CustomComponent 中的任何状态。

相反,组件应该自己声明,而不是在渲染内部声明,以便它们只创建一次然后重用。如有必要,您可以让组件接受 props 来自定义其行为:

const CustomComponent = (): JSX.Element => <h1>But can I do this?</h1>

export default function App() {
  return (
    <div className="App">
      <UsualExample />
      <CustomComponent />
    </div>
  );
}

有时,您可能会在单个组件中重复执行某些操作,并希望通过辅助函数来简化代码。没关系,但是您需要将其作为函数调用,而不是将其呈现为组件。

export default function App() {
  const customCode = (): JSX.Element => <h1>But can I do this?</h1>
  return (
    <div className="App">
      {customCode()}
      <UsualExample />
      {customCode()}
    </div>
  );
}

使用这种方法,react 将比较 &lt;h1&gt;&lt;h1&gt;,因此不需要重新挂载它。

【讨论】:

  • 感谢您的回答,这是有道理的,并且还详细说明了为什么在渲染性能方面这是一个坏主意。我们经常使用你上面提到的辅助函数方法,所以会坚持使用,或者你和 Adam 都提到,如果我们想要一个组件,只需抽象出另一个函数。
  • “辅助函数”与组件存在完全相同的问题。它们只需要关闭函数范围内可用的一些变量。只需将这些变量作为参数传递给辅助函数,然后从组件中提取辅助函数即可。在组件内部声明函数(不使用useCallback)是糟糕的性能、糟糕的设计、糟糕的一切。
  • "helper functions" suffer from the exact same issue as components 虽然肯定有反对辅助函数的论据,但它们确实不会受到元素类型不同的影响,因此它们不会导致协调器错误地认为元素变了。
  • @NicholasTower - 在上面的示例中,将 customCode() 更改为 &lt;customCode/&gt; 并看看会发生什么 - 这是一条非常非常细的线。你所做的是创建了一个组件(它返回 JSX 对吗?),但称它为不同的东西(它不是)所以现在它不能从 Reacts 的许多性能优化中受益。
  • 是的,我很清楚&lt;customCode/&gt;customCode() 有不同的结果。这几乎正​​是我回答的重点。
【解决方案2】:

这不仅是一个坏主意,而且是一个可怕的主意。你还没有发现作文(没关系,这需要一段时间,你会到达那里)。

您想要在另一个组件中声明一个组件的唯一原因是关闭您想要在子组件中捕获的prop(也可能是一些state) - 这是诀窍 - 通过它作为新组件的道具,然后您可以在 OUTSIDE 声明新组件。

转动这个:

function UsualExample() {
  return <h1>This is the standard example…</h1>
}

export default function App({someProp}) {
  // the only reason you're declaring it in here is because this component needs "something" that's available in <App/> - in this case, it's someProp
  const CustomComponent = (): JSX.Element => <h1>I'm rendering {someProp}</h1>
  return (
    <div className="App">
      <UsualExample />
      <CustomComponent />
    </div>
  );
}

进入这个:

function UsualExample() {
  return <h1>This is the standard example…</h1>
}

const CustomComponent = ({someProp}) => <h1>I'm rendering {someProp}></h1>

export default function App({someProp}) {
  return (
    <div className="App">
      <UsualExample />
      { /* but all you have to do is pass it as a prop and now you can declare your custom component outside */ }
      <CustomComponent someProp={someProp} />
    </div>
  );
}

【讨论】:

  • “这不仅是个坏主意,而且是个可怕的主意。” - 应该解释为什么。 “你还没有发现构图(没关系,这需要一段时间,你会到达那里)。” - 这有点傲慢和不必要,特别是因为 OP 表示“我已经开始看到我的一些团队编写以下代码”并且正在询问观察到的模式。并非所有语言或框架都对嵌套函数声明有优化问题,因此这不是已成定局。
猜你喜欢
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
  • 1970-01-01
  • 2020-05-27
  • 1970-01-01
  • 2021-10-04
  • 1970-01-01
  • 2020-12-27
相关资源
最近更新 更多