【问题标题】:React props: Should I pass the object or its properties? Does it make much difference?React props:我应该传递对象还是它的属性?它有很大的不同吗?
【发布时间】:2018-10-03 06:45:08
【问题描述】:

在传递 props 时,我应该将整个对象传递给子组件,还是应该先在父组件中单独创建 props,然后将这些 props 传递给子组件?

传递整个对象:

<InnerComponent object={object} />

先单独创建需要的道具:

<InnerComponent name={object.name} image={object.image} />

哪个是首选,如果取决于,我应该使用什么作为衡量标准?

【问题讨论】:

    标签: javascript reactjs react-props


    【解决方案1】:

    您应该更喜欢第二个示例,分别传递道具。 在那里,您可以明确地看到传递了哪些参数,并且可以快速与预期的参数进行比较。这使得人们之间的协作变得更加容易,并使应用程序的状态更加清晰。

    如果不需要,我个人会尽量避免传递整个对象。 这就像扩展运算符,其中可以有任何属性,并且在更大的范围内难以调试。

    prop-typestypescript 这样的纯反应添加可能有助于在大型应用程序中定义清晰和预期的属性

    【讨论】:

    • 所以这是可维护性的问题? React 是否会因为传递对象而不是属性而遭受任何明显的开销?
    【解决方案2】:

    根据the principle of least privilege,这是正确的方法:

    <InnerComponent name={object.name} image={object.image} />
    

    这限制了InnerComponent 意外修改原始对象或访问不适合它的属性。

    或者,可以从原始对象中挑选属性并作为道具传递:

    <InnerComponent {...pick(object, 'name', 'image')} />
    

    如果有许多属性难以列出,可能会有一个 prop 接受一个对象:

    <InnerComponent object={pick(object, 'name', 'image')} />
    

    【讨论】:

    • 也许很高兴添加 pick 是一个来自 lodash 的函数。由于在 JS 中生成对象的子集非常简单,当您想要 { name: name } 之类的东西时,可以省略 pick() 并简单地使用 {name, image},我猜 ...
    • @Xen_mar Lodash 是一个值得注意的例子,但它是任意挑选功能,可以是用户定义的单线,pick = (o, ...keys) =&gt; Object.fromEntries(Object.entries(o).filter(([k]) =&gt; keys.includes(k)))。解构需要上面有let {name, image} = object,由于JSX通常是如何编写的,这并不总是可行的,它可能是一个没有return的箭头。
    【解决方案3】:

    由于 JavaScript 没有类型注释,因此第二个选择会更可取,正如 @mstruebing 所提到的,代码将更易于维护。但是,如果您使用的是 TypeScript React(支持类型注释),那么两种选择都同样清楚。但请记住,第一选择促进了视图和模型之间的紧密耦合,这允许快速开发,因为您不必输入太多;虽然第二种选择可能会减慢开发速度,但您对未来的变化具有更高的灵活性和容忍度。

    因此,衡量标准是:如果您更喜欢开发速度而不是灵活性,请选择 1;如果您更喜欢灵活性而不是开发速度,请选择 2。

    补充说明

    好的,我们什么时候应该优先考虑开发速度而不是灵活性?这是我的 2 美分。

    如果您的项目是为了短期使用(例如开发一个仅用于在选举期间收集选票的应用程序),那么请选择第一选择。

    如果您的项目是为了长期使用(例如在线银行交易门户),您应该选择第二个选择。

    【讨论】:

    • 也是我的 2 美分:根据经验,我认为通常值得花时间选择选择 2,因为它不会 比选择 1 长。你会当您意识到您的应用不再用于短期使用(几乎总是这样结束)时,可以节省大量时间
    【解决方案4】:

    将多个 props 传递给子组件是将 props 传递给子组件的首选方式。这将帮助您跟踪子组件中应用程序的状态。 另外,请随意使用prop-types 模块。它的作用类似于 Java 中的泛型,并为传入的 props 提供类型安全。

    【讨论】:

      【解决方案5】:

      如果您没有使用对象中的所有属性,最好单独传递所需的属性,因为当Child 组件是使用shouldComponentUpdatePureComponent 时,它有助于性能优化。在这种情况下,只有当Child 组件使用的道具发生变化时,它才会重新渲染,而不是当对象内未使用的属性发生变化时。

      但是,如果您正在使用对象中的所有属性,那么如果您将对象作为道具传递下去,只要您正确处理对象的突变,它就不会产生太大的影响。

      【讨论】:

      • 如果我们传递一个对象,重新渲染将仅取决于整个对象何时更改,而不是单个属性
      【解决方案6】:

      这取决于那个对象。您是否需要将其所有属性传递给另一个组件?或者...您可能需要将 5 个属性中的 2 个传递给特定组件?

      • 如果你不需要传递它的所有属性,我建议传递 PropertiesProps
      • 但是,如果您 100% 确定您需要所有属性 一起传递,我建议将整个Object 传递为Props in 这种情况,因为它会更清晰的代码,让你远离 忘记传递一些东西。例如;添加新属性时 到那个对象,你不必通过它,因为你已经通过了 整个对象!

      好吧,如果您不确定该对象的当前/未来用途,因为您可能需要尽快排除某些属性,那么您可能应该在这种情况下单独传递其属性,而不是将一些未使用的属性传递给另一个组件。

      【讨论】:

        【解决方案7】:

        我同意其他答案,简而言之,视情况而定,其他答案中提出的观点都是有效的。

        我想补充的其他一些也倾向于使用单个属性的点如下 -

        • 有时甚至不是我是否需要所有属性的问题?这应该是更多的问题 - 我是否想将组件的使用限制在我只有完整的对象而不仅仅是属性的子集时。

        以一个小部件为例,它显示汽车的图像、品牌和型号作为小部件列表的一部分,期望 full Car 类型可用以仅显示汽车的图像、品牌和型号。只有这 3 个属性是必需的。

        • 随着 graphql 之类的兴起,我们可以限制返回的关于类型的数据的属性,我们不应该总是假设组件可以访问基于类型的完全填充的对象。

        • 最后,关于导致组件在树下不必要的重新渲染,总是传递完整的对象,当对象更新时,您可能会导致使用该对象的所有子级重新渲染。然而,将单独的属性传递给孩子,通常是原语,我们可以更好地减少不必要的重新渲染

        【讨论】:

        • 关于不必要的重新渲染的最后一点。如果 prop 发生变化,是不是意味着父组件更新了呢?它更新了这个道具,因为它的状态发生了变化,导致父组件重新渲染。所以无论如何它都会重新渲染,并渲染孩子,不管我们是否将整个对象或它的一部分作为道具传递,不是吗?我的问题是:重新渲染真的依赖于 parent->child 道具类型(对象,原语)吗?
        • 不一定,如果一个父级重新渲染并且一个子级(使用memo)接收与以前相同的道具(即相同的原始值或相同的对象/数组引用)它不会重新渲染子级。我的观点是,将原始值作为道具进行浅层比较要安全得多,因此可以防止深度不必要的重新渲染,而将对象和数组作为道具传递,意外地将新对象/数组引用作为道具传递和在这种情况下,孩子重新渲染
        • 现在我明白你的意思了。是的,我同意。
        【解决方案8】:

        对象的全部意义在于将相似的属性封装在一起。如果您有大约 10 个属性并想在子组件中使用它们,请坚持使用对象。

        但在您的情况下,我的意见是使用您的第二个示例,因为它使子组件中的代码更简单。

        为了两全其美,只需在子组件中解构您需要的那些道具。

        像这样:

        function InnerComponent({ name, image }) {
          ...
        }
        

        如果您不喜欢参数中的大括号,请执行以下操作:

        function InnerComponent(props) {
          const { name, image } = props;
          ...
        }
        

        【讨论】:

          猜你喜欢
          • 2018-09-19
          • 2022-10-25
          • 2022-12-11
          • 1970-01-01
          • 1970-01-01
          • 2011-05-24
          • 1970-01-01
          • 2014-12-09
          • 2020-06-10
          相关资源
          最近更新 更多