如何为使用 withRouter 包裹的组件定义 propTypes?

How to define propTypes for a component wrapped with withRouter?

我想知道在将用第 3 方 HOC 包装的组件上定义 propTypes 的最佳实践是什么,在这种情况下,withRouter() 来自 React-Router .

据我了解,propTypes 的目的是让您(和其他开发人员)知道组件应该期待什么道具,如果违反,React 会发出警告。

因此,关于位置的 props 已经被 withRouter() 传递,没有人为干预,这里还有必要担心它们吗?

这是我正在使用的组件:

const Menu = ({ userId, ...routerProps}) => {

  const { pathname } = routerProps.location
  return (
      // Something using userID
      // Something using pathname
  )
}

Menu.propTypes = {
  userId: PropTypes.number.isRequired,
  // routerProps: PropTypes.object.isRequired,
  // ^ this is undefined, bc withRouter passes it in later?
}

export default withRouter(Menu)

//.... in parent:
<Menu userId={id} />

这种情况下的惯例是什么?

It is my understanding that the point of propTypes is so you (and other developers) know what props a component should expect, and React will give warnings if this is violated.

这是正确的。

What would be the convention in this case?

我认为您不会找到明确的答案。有些人会争辩说,如果你定义一个 propType 你应该定义所有预期的道具类型。其他人会像您一样说,它不会由父组件(不包括 HOC)提供,所以何必呢。还有一类人会告诉你根本不用担心 propTypes...

就个人而言,我属于第一类或最后一类:

  • 如果组件是供其他人使用的,例如通用 ui 组件(例如 TextField、Button 等)或库的界面,那么 propTypes 很有帮助,你应该定义它们。
  • 如果组件仅用于特定目的,在单个应用程序中,那么通常根本不用担心它们,因为在传递错误的 props 时,您将花费更多的时间来维护它们而不是调试 (特别是如果您正在编写小型、易于使用的功能组件。

包含 routerProps 的论点是为了保护您免受 withRouter 提供的道具在未来发生变化时的影响。

因此,假设您想为 withRouter 添加 propTypes,那么我们需要细分它们实际应该是什么:

const Menu = ({ userId, ...routerProps}) => {
  const { pathname } = routerProps.location
  return (
      // Something using userID
      // Something using pathname
  )
}

查看上面的代码片段,您可能认为 propTypes 应该是

Menu.propTypes = {
  userId: PropTypes.number.isRequired,
  routerProps: PropTypes.object.isRequired
}

但您会误会...前两行包含大量 props 转换。其实应该是

Menu.propTypes = {
  userId: PropTypes.number.isRequired,
  location: PropTypes.shape({
    pathname: PropTypes.string.isRequired
  }).isRequired
}

为什么?该片段等价于ui等于:

const Menu = (props) => {
  const userId = props.userId
  const routerProps = Object.assign({}, props, { userId: undefined }
  const pathname = routerProps.location.pathname
  return (
      // Something using userID
      // Something using pathname
  )
}

如您所见,routerProps 实际上根本不存在于 props 中。 ...routerProps 是一个 rest parameter,所以它得到 props 的所有其他值,在这种情况下,location(可能还有其他你不关心的事情)。

希望对您有所帮助。