在 React 中,我可以在另一个功能组件的主体中定义一个功能组件吗?

In React, can I define a functional component within the body of another functional component?

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

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

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

相反,组件应该自己声明,而不是在渲染过程中声明,这样它们只创建一次然后就可以重复使用。如有必要,您可以让组件接受道具来自定义其行为:

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 会将 <h1><h1> 进行比较,因此不需要重新挂载它。

这不仅是个坏主意,还是个糟糕的主意。您还没有发现组合(没关系,需要一段时间,您会到达那里)。

你想要在另一个组件中声明一个组件的唯一原因是关闭你想要在子组件中捕获的 prop(也许还有一些 state) - 这是诀窍 - 将其作为道具传递给新组件,然后您可以在外部声明新组件。

转这个:

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>
  );
}