React 使用 PropTypes 进行类型检查

2021-07-20 0 By admin

随着你的应用程序不断增长,你可以通过类型检查捕获大量错误。在开发中,可以选择使用 Flow 或 TypeScript 等扩展来做类型检查;也可以使用,React 内置的一些类型检查的功能。
要在组件的 props 上进行类型检查,你只需配置特定的 propTypes 属性即可。

一、示例

import PropTypes from 'prop-types';

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

Greeting.propTypes = {
  name: PropTypes.string
};

PropTypes 提供一系列验证器,可用于确保组件接收到的数据类型是有效的。
在本例中, 我们使用了 PropTypes.string。当传入的 prop 值类型不正确时,JavaScript 控制台将会显示警告。
出于性能方面的考虑,propTypes 仅在开发模式下进行检查。

二、PropTypes 各种类型介绍

2.1、JS 原生类型

MyComponent.propTypes = {
  // 可以将属性声明为 JS 原生类型,默认情况下这些属性都是可选的。
  optionalArray: PropTypes.array,
  optionalBool: PropTypes.bool,
  optionalFunc: PropTypes.func,
  optionalNumber: PropTypes.number,
  optionalObject: PropTypes.object,
  optionalString: PropTypes.string,
  optionalSymbol: PropTypes.symbol,
};

2.2、可被渲染的元素和React 元素类型

// 任何可被渲染的元素(包括数字、字符串、元素或数组)(或 Fragment) 也包含这些类型。
  optionalNode: PropTypes.node,

// 一个 React 元素。
  optionalElement: PropTypes.element,

// 一个 React 元素类型(即,MyComponent)。
  optionalElementType: PropTypes.elementType,

2.3、复杂类型的组合

// 你也可以声明 prop 为【类的实例】,这里使用 JS 的 instanceof 操作符。
  optionalMessage: PropTypes.instanceOf(Message),

// 你可以让你的 prop 只能是特定的值,指定它为【枚举类型】。
  optionalEnum: PropTypes.oneOf(['News', 'Photos']),

// 一个对象可以是【几种类型中的任意一个类型】
  optionalUnion: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.instanceOf(Message)
  ]),

// 可以指定一【个数组由某一类型的元素组成】
  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

// 可以指定【一个对象由某一类型的值组成】
  optionalObjectOf: PropTypes.objectOf(PropTypes.number),

// 可以指定【一个对象由特定的类型值组成】
  optionalObjectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number
  }),

// An object with warnings on 【extra properties】
  optionalObjectWithStrictShape: PropTypes.exact({
    name: PropTypes.string,
    quantity: PropTypes.number
  }),

2.4、isRequired 必填项

// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保这个 prop 没有被提供时,会打印警告信息。
  requiredFunc: PropTypes.func.isRequired,

// 任意类型的必需数据
  requiredAny: PropTypes.any.isRequired,

2.5、自定义验证器

// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
// 请不要使用 `console.warn` 或抛出异常,因为这在 `oneOfType` 中不会起作用。
  customProp: function(props, propName, componentName) {
    if (!/matchme/.test(props[propName])) {
      return new Error(
        'Invalid prop `' + propName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  },

  // 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
  // 它应该在验证失败时返回一个 Error 对象。
  // 验证器将验证数组或对象中的每个值。验证器的前两个参数
  // 第一个是数组或对象本身
  // 第二个是他们当前的键。
  customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
    if (!/matchme/.test(propValue[key])) {
      return new Error(
        'Invalid prop `' + propFullName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  })

三、限制props 传输的为单个元素

你可以通过 PropTypes.element 来确保传递给组件的 children 中只包含一个元素。

import PropTypes from 'prop-types';

class MyComponent extends React.Component {
  render() {
    // 这必须只有一个元素,否则控制台会打印警告。
    const children = this.props.children;
    return (
      <div>
        {children}
      </div>
    );
  }
}

MyComponent.propTypes = {
  children: PropTypes.element.isRequired
};

四、为 Props 设置默认值

您可以通过配置特定的 defaultProps 属性来定义 props 的默认值:

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

// 指定 props 的默认值:
Greeting.defaultProps = {
  name: 'Stranger'
};

// 渲染出 "Hello, Stranger":
ReactDOM.render(
  <Greeting />,
  document.getElementById('example')
);

如果你正在使用像 transform-class-properties 的 Babel 转换工具,你也可以在 React 组件类中声明 defaultProps 作为静态属性。
此语法提案还没有最终确定,需要进行编译后才能在浏览器中运行。要了解更多信息,请查阅 class fields proposal。

class Greeting extends React.Component {
  static defaultProps = {
    name: 'stranger'
  }

  render() {
    return (
      <div>Hello, {this.props.name}</div>
    )
  }
}

defaultProps 用于确保 this.props.name 在父组件没有指定其值时,有一个默认值。propTypes 类型检查发生在 defaultProps 赋值后,所以类型检查也适用于 defaultProps。

五、函数组件中的使用方法

如果你在常规开发中使用函数组件,那你可能需要做一些适当的改动,以保证 PropsTypes 应用正常。

5.1、假设你有如下组件

export default function HelloWorldComponent({ name }) {
  return (
    <div>Hello, {name}</div>
  )
}

5.2、第二步

如果要添加 PropTypes,你可能需要在导出之前以单独声明的一个函数的形式,声明该组件,具体代码如下:

function HelloWorldComponent({ name }) {
  return (
    <div>Hello, {name}</div>
  )
}
export default HelloWorldComponent

5.3、最后一步

可以直接在 HelloWorldComponent 上添加 PropTypes:

import PropTypes from 'prop-types'

function HelloWorldComponent({ name }) {
  return (
    <div>Hello, {name}</div>
  )
}

HelloWorldComponent.propTypes = {
  name: PropTypes.string
}

export default HelloWorldComponent