【问题标题】:How to define propTypes for a component wrapped with withRouter?如何为 withRouter 封装的组件定义 propTypes?
【发布时间】:2024-05-19 06:40:01
【问题描述】:

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

据我了解,propTypes 的目的是让您(和其他开发人员)知道组件应该期望什么 props,如果违反,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} />

这种情况下的约定是什么?

【问题讨论】:

    标签: javascript reactjs react-router higher-order-components


    【解决方案1】:

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

    这是正确的。

    这种情况下的约定是什么?

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

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

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

    包含routerProps 的理由是为了保护您免受withRouter 提供的道具在将来发生变化时发生的变化。

    因此,假设您想将propTypes 包含在withRouter 中,那么我们需要分解它们实际上应该是什么:

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

    看了上面的sn-p,你可能觉得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
    }
    

    为什么? sn-p 相当于:

    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 中。 ...routerPropsrest parameter,因此它获取了 props 的所有其他值,在本例中为 location(可能还有其他你不关心的东西)。

    希望对您有所帮助。

    【讨论】:

    • 谢谢,这行得通。我不确定我能否同时获得普通道具和 HOC 道具。