如何减少传入的反应道具数量
How to reduce the number of react props pass in
随着 React Web 应用程序变得复杂,一些组件有一些 props,可读性较差,更难预期该组件的功能,并且添加大量 prop 类型检查和从最顶层组件传递 props 是乏味的到底部。这主要是由于从上到下传递 flux/redux 操作和存储造成的。
有什么好的方法可以减少传入的 props 数量吗?
我想到了两个解决方案,都不是很完美:
使用扩展运算符 {...props} 传递 props。这样确实减少了写一些 props 和 prop type 的检查,但是命名可能会有冲突,所以 actions/stores 的名字应该是唯一的。另一个缺点是要格外小心传递或不传递什么道具以避免副作用。
用容器包装组件,容器直接将 actions/stores 连接到组件,以临时方式。例如,可以使用react-redux
的connect()
。这比解决方案 #1 更干净、更简单,但如果组件包含容器,则很难编写组件测试,因为 Redux 错误。
错误示例之一是
Invariant Violation: Could not find "store" in either the context or props of "Connect(Header)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Header)".
您已经很好地描述了两种方法及其优缺点。我将在您所说的基础上添加一些设计注意事项。
方法 #2 是我的首选方法。减少通过组件的道具数量可以避免复杂性。有一些方法可以在不触发该错误的情况下测试组件,但老实说,我认为这值得单独提出 Stack Overflow 问题。现在,我只想说看看浅层渲染,并考虑你是否真的需要在这里进行单元测试而不是集成测试。如果您还将使用诸如 Selenium 之类的东西创建自动化测试,那么它也许可以作为您的集成测试。
可以通过谨慎使用 PropTypes 来验证正在传递的内容来改进方法 #1。省略 PropTypes 检查只是传递 ...props 的中间组件是合理的,但最终组件(实际使用 props 而不是仅仅传递的组件)应该有非常严格的 PropTypes 声明。使用形状而不是对象。使用 ArrayOf 而不是 Array,基本上抓住所有机会在 PropTypes 声明中具体化。
考虑到您对名称冲突的担忧,有时将 props 组合在一起作为一个对象的成员并将该对象作为单个 prop 传递会有所帮助。如果 props 在概念上是相关的或者只有一个目标组件,这是有道理的。我仍然非常喜欢只拥有更多的容器组件(方法 #2),因为它会导致更少的信息流经 props。为具有嵌套成员的对象编写良好的 PropTypes 需要更多时间,并产生需要更长时间才能解决问题的警告消息。
人们有时会在开始使用 Redux/Flux 后忘记 .state,一些纯粹主义者更喜欢通过商店发送和接收所有内容。无状态组件声明的优雅进一步使我反对将 .state 添加到组件。但是 .state 非常适合跟踪短暂的事物,例如动画和工具提示可见性。不是所有东西都需要在商店里通过道具。
随着 React Web 应用程序变得复杂,一些组件有一些 props,可读性较差,更难预期该组件的功能,并且添加大量 prop 类型检查和从最顶层组件传递 props 是乏味的到底部。这主要是由于从上到下传递 flux/redux 操作和存储造成的。
有什么好的方法可以减少传入的 props 数量吗?
我想到了两个解决方案,都不是很完美:
使用扩展运算符 {...props} 传递 props。这样确实减少了写一些 props 和 prop type 的检查,但是命名可能会有冲突,所以 actions/stores 的名字应该是唯一的。另一个缺点是要格外小心传递或不传递什么道具以避免副作用。
用容器包装组件,容器直接将 actions/stores 连接到组件,以临时方式。例如,可以使用
react-redux
的connect()
。这比解决方案 #1 更干净、更简单,但如果组件包含容器,则很难编写组件测试,因为 Redux 错误。 错误示例之一是
Invariant Violation: Could not find "store" in either the context or props of "Connect(Header)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Header)".
您已经很好地描述了两种方法及其优缺点。我将在您所说的基础上添加一些设计注意事项。
方法 #2 是我的首选方法。减少通过组件的道具数量可以避免复杂性。有一些方法可以在不触发该错误的情况下测试组件,但老实说,我认为这值得单独提出 Stack Overflow 问题。现在,我只想说看看浅层渲染,并考虑你是否真的需要在这里进行单元测试而不是集成测试。如果您还将使用诸如 Selenium 之类的东西创建自动化测试,那么它也许可以作为您的集成测试。
可以通过谨慎使用 PropTypes 来验证正在传递的内容来改进方法 #1。省略 PropTypes 检查只是传递 ...props 的中间组件是合理的,但最终组件(实际使用 props 而不是仅仅传递的组件)应该有非常严格的 PropTypes 声明。使用形状而不是对象。使用 ArrayOf 而不是 Array,基本上抓住所有机会在 PropTypes 声明中具体化。
考虑到您对名称冲突的担忧,有时将 props 组合在一起作为一个对象的成员并将该对象作为单个 prop 传递会有所帮助。如果 props 在概念上是相关的或者只有一个目标组件,这是有道理的。我仍然非常喜欢只拥有更多的容器组件(方法 #2),因为它会导致更少的信息流经 props。为具有嵌套成员的对象编写良好的 PropTypes 需要更多时间,并产生需要更长时间才能解决问题的警告消息。
人们有时会在开始使用 Redux/Flux 后忘记 .state,一些纯粹主义者更喜欢通过商店发送和接收所有内容。无状态组件声明的优雅进一步使我反对将 .state 添加到组件。但是 .state 非常适合跟踪短暂的事物,例如动画和工具提示可见性。不是所有东西都需要在商店里通过道具。