React:变量中的 jsx 与函数与单独的组件

IT技术 javascript html reactjs jsx
2021-05-02 07:36:06

为了在更大的组件中渲染更小的组件/jsx,有多种方法可以遵循。例如,考虑这个:

方法一:

function BigComponent(props) {
  const renderSmallComponent1 = () => <div>{props.a}</div>;
  const renderSmallComponent2 = () => <div>{props.b}</div>;

  return (
    <div>
      {renderSmallComponent1()}
      {renderSmallComponent2()}
    </div>
  )
}

方法二:

function BigComponent(props) {
  const smallComponent1 = <div>{props.a}</div>;
  const smallComponent2 = <div>{props.b}</div>;

  return (
    <div>
      {smallComponent1}
      {smallComponent2}
    </div>
  )
}

方法三:

function SmallComponent1({ a }) {
  return <div>{a}</div>;
}

function SmallComponent2({ b }) {
  return <div>{b}</div>;
}

function BigComponent(props) {
  return (
    <div>
      <SmallComponent1 a={props.a} />
      <SmallComponent2 b={props.b} />
    </div>
  )
}

我只是想了解这三个方面的区别

  • 开发经验,
  • 框架如何对待他们,
  • 有没有性能优化,
  • 所有这些中的运行时行为是否存在差异?
  • 在某些情况下使用哪个更好?

这些是我理解的事情:

  • 方法3中SmallComponent都是React组件,在另一个组件中渲染,所以会有组件生命周期,而方法1和方法2是简单的jsx,没有生命周期,所以不会挂载/卸载react组件
  • 在方法 2 中,我们会急切地评估 JSX,因为它直接是一个变量,而在方法 1 中,它只会在渲染中调用函数时进行评估。所以,万一我们有任何条件渲染,急切的评估可能只是浪费。

其他一些有用的文章:

更新:似乎观察 1 是不正确的,因为它们中的所有 3 仍将呈现为react组件,因此将具有组件生命周期。所以 react 会挂载/卸载它们。

更新 2:不,观察 1 是正确的,方法 1 和 2 都被视为常规 jsx 作为 BigComponent 的一部分,它们不被视为具有生命周期的react组件。

更新3:还有另一种方法方法4:

function BigComponent(props) {
  const SmallComponent1 = () => {
  return <div>{props.a}</div>;
  }
  const SmallComponent2 = () => {
  return <div>{props.b}</div>;
  }

  return (
    <div>
      <SmallComponent1 />
      <SmallComponent2 />
    </div>
  )
}

这与方法 3 类似,但是通过开发工具进行调试时,方法 3 与方法 4 在执行上略有不同。

2个回答

方法二:

function BigComponent(props) {
  const smallComponent1 = <div>{props.a}</div>;
  const smallComponent2 = <div>{props.b}</div>;

  return (
    <div>
      {smallComponent1}
      {smallComponent2}
    </div>
  )
}
  • 如果你想把一个大的 UI 变成单独的小 UI,这个方法会给你最好的性能,因为
    • 它仍然只是一个大的 UI 组件。
    • react只需要解决变量引用。
    • 在重新渲染时,BigComponent、smallComponent1 和 smallComponent2 作为一个单元一起渲染。
    • smallComponent1 和 smallComponent2 不能有自己的状态、生命周期和钩子。
    • 每次 Bigcomponent 状态改变时,smallComponent1 和 2 都需要重新初始化因此,useMemo()如果这些 smallComponents 的结果来自昂贵的计算,那么最好将它们包装起来

方法三:

function SmallComponent1({ a }) {
  return <div>{a}</div>;
}

function SmallComponent2({ b }) {
  return <div>{b}</div>;
}

function BigComponent(props) {
  return (
    <div>
      <SmallComponent1 a={props.a} />
      <SmallComponent2 b={props.b} />
    </div>
  )
}
  • React 需要解析引用并在解析引用后执行函数。

  • 它是将 react 的实际子组件组合成一个大组件。

  • 允许子组件拥有自己的hooks.

  • 子组件不会重新初始化,但会在 BigComponent 状态更改时重新呈现。

  • 如果小组件根据父组件中的 props 更改更新它们自己的状态,则 SmallComponent1 和 SmallComponent2 有可能在 BigComponents 渲染一次时重新渲染多次。

  • 如果每个 SmallComponents 应该使用 BigComponents 状态的多个 props,将 SmallComponents 保留在 BigComponent 之外确实提供了良好的开发体验。

  • 我希望通过以上几点也可以理解方法一和方法四。

  • 注意:如果您的应用程序逻辑使用 ref 或 DOM 元素来维护渲染的焦点或锚点,则存储在变量中的子组件和作为函数的子组件会变得更复杂。

有没有在 React 项目中查看过编译后的 JS?

JSX 标签本质上转换为React.createElement语句。您可以在此处阅读文档本质上的语法是:

React.createElement(FunctionOrClassComponent, { props }, ...children)

在您的所有三个示例中,这都会发生。在所有三个示例中,较小的组件是功能组件而不是类组件。也就是说,它们没有类组件的 React 生命周期方法,但它们可以使用等效的 React 钩子 - 如果您愿意的话。

编辑:评估(实例化和渲染)取决于您的渲染逻辑。如果您有条件呈现语句或您的函数根据某些条件返回 null(或更少的内容),那么显然您所做的工作更少。正如您在下面的评论中正确指出的那样,当您将 JSX.Element 分配给一个变量时,它是内联计算的,而不是作为函数的结果 - 所以这会立即发生。

对我来说,这三种方法都是有效的方法。要解决您的问题:

  • 开发经验,
    • 对于具有最少状态的小组件,作为变量或 lambda 的函数组件在以后重新访问代码时易于编写和轻松读取/解析。当组件变得更加复杂时,您可能不得不重新考虑它的编写方式,并且可能需要使用 Class 组件。
  • 框架如何对待他们,
    • 据我所知,该框架在编译方面对所有三个示例的处理方式相同。我不确定渲染优化。
  • 有没有性能优化,
    • 你的例子没有描述任何计算繁重的东西,所以性能优化选项不是那么明显
  • 所有这些中的运行时行为是否存在差异?
    • 它们都被转换为 React 元素,监视 props 的变化,并在父级重新渲染时重新渲染(如果没有使用 React.memo 之类的东西)——与基于类的元素可能存在差异,但我猜您的三个示例之间的运行时差异很小
  • 在某些情况下使用哪个更好?
    • 这三者之间的差异更多是标准或礼仪问题,而不是功能结果。作为一名开发人员,我将能够阅读和理解这三者,但在团队中工作 - 我希望看到一种标准方法。