【问题标题】:React: jsx in a variable vs a function vs a separate componentReact:变量中的 jsx vs 函数 vs 单独的组件
【发布时间】:2021-07-15 00:35:31
【问题描述】:

为了在更大的组件中渲染更小的组件/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 会挂载/卸载它们。

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

更新 3: 还有一种方法方法四:

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在执行上略有不同,通过开发工具调试时。

【问题讨论】:

  • 您似乎很了解这些案例。我不确定您想深入挖掘哪个特定方面?
  • 诸如此类的问题:是否存在其中一种方法的工作方式与其他方法不同或根本不起作用的情况?它们总是可以互相替换吗?
  • 嗯,这对我来说仍然是一个悬而未决的问题。我真的不知道从哪里开始,因为我可以构建各种示例来说明差异行为。
  • @hackape 我认为不同类型的示例仍然会有所帮助,并且可能会回答问题的主要部分,这本质上是关于这三种方法的差异
  • 我认为更好的方法是学习 react 的内部工作,而不是仔细检查特殊的用例。一旦你学会了“物理学”,你就会知道如何做所有的“工程”。

标签: javascript html reactjs jsx


【解决方案1】:

方法二:

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 不能有自己的状态、生命周期和挂钩。
    • smallComponent1 和 2 需要在每次 Bigcomponent 状态更改时重新初始化。因此,如果这些 smallComponents 的结果来自昂贵的计算,最好用 useMemo() 包装它们。

方法三:

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 元素来维护渲染的焦点或锚点,则作为函数存储在变量和子组件中的子组件会变得更加复杂。

【讨论】:

    【解决方案2】:

    你看过 React 项目中编译好的 JS 吗?

    JSX 标签本质上被转换为React.createElement 语句。你可以read the docs here。本质上的语法是:

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

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

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

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

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

    【讨论】:

    • 关于急切评估:方法 1 只会在函数在渲染/返回中调用时评估事物,但方法 2 甚至会在此之前评估事物,因为它是一个变量
    • 关于使用钩子:在方法1和2中,我认为即使我们能够使用钩子,它们也属于父级,而不是这些小组件。
    • 抱歉,来晚了——我把你所说的评估与急切加载(而不是延迟加载)混淆了。你是对的,方法 2 会评估内联的东西,因为它们不是函数,而是 JSX 元素声明(作为变量)。对于方法 1 和 3,如果您在小组件中使用了钩子,并且您声明并将钩子输出分配给块作用域变量(使用 let 或 const),它们将属于小组件......它们只会提升到父组件如果你使用了 var.
    • 对不起,那里也犯了一个错误......我的意思是说,如果你在那里声明它们,它们只会属于父组件。
    猜你喜欢
    • 2019-06-03
    • 2021-09-06
    • 2018-04-27
    • 2019-01-22
    • 2021-03-01
    • 2014-08-08
    • 2019-04-02
    • 2011-06-21
    • 2021-12-27
    相关资源
    最近更新 更多