【问题标题】:How to define propTypes for a Component that only passes props to a Child如何为仅将 props 传递给 Child 的组件定义 propTypes
【发布时间】:2020-04-04 14:00:35
【问题描述】:

在 Parent 中定义 proptypes 的最佳实践是什么?只将 props 传递给 Child 而不使用它?

简单用例:

const Parent = ({ p0, p1 }) => (
  <section className="Parent">
    <div>I'm the parent</div>
    <p>{p0}</p>
    <Child p1={p1} />
  </section>
);

Parent.propTypes = {
  p0: PropTypes.string.isRequired,
  // p1 ?
};

还有子组件:

const Child = ({ p1 }) => (
  <section className="Child">
    <div>I'm a Child</div>
    <span>{p1}</span>
  </section>
);

Child.propTypes = {
  p1: PropTypes.string.isRequired,
};

这里是父选项:

  1. 不要定义 p1 propTypes 并使用 // disable-eslint-next-line react/propTypes
  2. p1: PropTypes.any.isRequired
  3. p1: Child.propTypes.p1(如果 Child 使用 React.memo 导出怎么办?)
  4. 使用与 Child p1: PropTypes.string.isRequired 相同的类型(如果 Child 有 10 个道具,复制所有道具类型会很无聊)
  5. 其他解决方案

在线示例: https://codesandbox.io/s/muddy-bush-3u243

【问题讨论】:

  • 如果Parent 只是一个传递,则只使用上下文(不使用p1

标签: reactjs eslint react-proptypes


【解决方案1】:

我理解你的代码的方式,即使是艰难的p1 被传递给Child,它仍然是Parent 实现的一部分仍然。从逻辑上讲,Parent 也是需要的。

所以你也必须在Parent的道具类型中定义它是正确的。

但我知道代码可能很乏味,但这更多的是风格问题而不是技术正确性问题,而且随着范式和品味一直在变化,风格很容易发生变化。所以我想这里没有正确或错误的答案,只有口味。

当然,这里有一些您可以应用的概念。总是有关于耦合或解耦代码的讨论,后者有时提倡代码重复(复制道具类型)。但是,如果您更改组件而不是其他组件,那么您的道具类型可能会不同步。

我个人会从 Child 加载 prop 类型,然后将要使用的 prop 类型合并到 parent 中:

import Child from "./Child";

const Parent = ({ p0, p1 }) => {/* ... */}

const { p1 } = Child.propTypes;

Parent.propTypes = {
  p0: PropTypes.string.isRequired,
  p1
};

【讨论】:

  • 另外请注意,如果您使用 TypeScript,所有这些都是隐式的,有时您会将 prop 接口放入您可以导入的自己的文件中。后者你也可以在这里做。
  • 谢谢,根据你的例子,如果 Child 被包裹怎么办?示例:导出默认 React.memo(Child);
  • 然后可以通过React.memo(Child).type.propTypes 访问它们,请参阅codesandbox.io/s/zen-smoke-niffo 中的Parent.js,但我不建议您这样做。然后,我们处于黑客和反模式的领域。您可以将道具类型设为自己的导出,请参阅该沙箱中的Child.js,但这似乎也很糟糕。然后我们又回到了你必须比较代码样式的地方。
【解决方案2】:

我认为您可以从 Parent propTypes 扩展 Child propTypes

Parent.propTypes = {
  ...{
    p0: PropTypes.string.isRequired
  }, ...Child.propTypes
};

我认为这应该可行。

附:我知道这段代码看起来不太好,但你可以使用像 lodash 或 Object.assign 这样的库来让它更漂亮。甚至可以创建一个方法来扩展 propTypes。

希望对你有帮助

【讨论】:

  • 你的第一次传播不是必需的:Parent.propTypes = { p0: PropTypes.string.isRequired ...Child.propTypes }; 但如果 Child 被包装它将不起作用(例如:export default React.memo(Child))
  • 在这种情况下,您可以创建一个接口并将其导出,即export const ChildPropTypes = PropTypes.shape({ p1: PropTypes.string.isRequired, }); 然后Parent.propTypes = { { p0: PropTypes.string.isRequired }, ...ChildPropTypes }; 感谢您的反馈!
【解决方案3】:

我会说这取决于道具的性质:

案例 1:props 是应用程序的重要数据/状态

在这种情况下,我会说需要父母和孩子的道具。

案例2:道具是孩子需要的,但不是那么重要——也就是说,父母也可以自己补

在这种情况下,我建议你不需要道具。设置道具类型和设置默认道具。

注意:在任何一种情况下,对子项和父项都使用相同的道具类型,以确保应用程序的可预测性。允许父级使用任何道具类型并要求子级使用字符串会在应用程序中造成混乱 - 确定在哪里期望哪种类型的数据总是比鼓励歧义要好。

第二个注意事项:如果您发现自己将多个 props 从父级传递给子级(假设父级期望 10 个道具,而您将 8 个传递给子级),您可能需要重构代码摆脱父母,因为她可能并不那么重要 - 但当然你是这里重要程度的判断者。

第三个注意事项:谨慎使用禁用 react prop-types。这是避免问题的一种快速方法,但它也是一种创建应用程序的简单方法,您不知道在其中流动的是哪种类型的数据。

【讨论】:

    猜你喜欢
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    • 2018-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多