Skip to content

属性默认值和类型验证

在 Vue 中,我们可以针对 props 属性进行类型验证,那么在 React 中同样也能对 props 进行验证。

官网文档地址:https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html

从 React v15.5 开始,React.PropTypes 被弃用,取而代之的是 prop-types 库。

prop-types 库地址:https://www.npmjs.com/package/prop-types

有关 props 验证这一块,我们主要搞清楚以下几个知识点:

  • 提供了哪些验证类型
  • 如何设置默认值

验证类型

有关 props 能够验证的类型,官网实际上已经全部罗列出来了。

基本验证与自定义验证

JSX
import PropTypes from 'prop-types';
import React from 'react';

function ChildCom(props) {
  return (
    <div>
      这里是一个子组件
      <hr />
      <span>
        {props.name} - {props.age}
      </span>
    </div>
  );
}

ChildCom.propTypes = {
  name: function (props, propName, componentName) {
    if (!/stu/.test(props[propName])) {
      return new Error(
        'Invalid prop `' +
          propName +
          '` supplied to' +
          ' `' +
          componentName +
          '`. Validation failed.'
      );
    }
  },
  age: PropTypes.number
};

export default ChildCom;
JavaScript
import ChildCom from './components/ChildCom';

function App() {
  return (
    <div className="App">
      {/* 错误1:缺少必须的 age 属性 */}
      {/* Warning: Failed prop type: Invalid prop `name` supplied to `ChildCom`. Validation failed. */}
      <ChildCom name="tom" age={11} />

      {/* 错误2:错误类型 age 传了字符串 */}
      {/* Warning: Failed prop type: Invalid prop `age` of type `string` supplied to `ChildCom`, expected `number`. */}
      <ChildCom name="stu-test" age="12" />
    </div>
  );
}

export default App;

数组类型验证

对于对象类型的验证,此处不做过多介绍,只介绍数组类型的验证。

JSX
import PropTypes from 'prop-types';
import React from 'react';

function ChildCom(props) {
  return (
    <>
      <h1>这里是一个子组件</h1>
    </>
  );
}

ChildCom.propTypes = {
  score: PropTypes.arrayOf(
    function (propValue, key, componentName, location, propFullName) {
      if (typeof propValue[key] !== 'number') {
        return new Error(
          'Invalid prop `' +
            propFullName +
            '` supplied to `' +
            componentName +
            '`. Expected `number`.'
        );
      }
    }
  )
};

export default ChildCom;
JavaScript
import ChildCom from './components/ChildCom';

function App() {
  return (
    <div className="App">
      {/* Warning: Failed prop type: Invalid prop `score[1]` supplied to `ChildCom`. Expected `number`. */}
      <ChildCom score={[98, '97', 100]} />
    </div>
  );
}

export default App;

插槽效果验证

JSX
import PropTypes from 'prop-types';
import React from 'react';

function ChildCom(props) {
  return (
    <>
      <h1>这里是一个子组件</h1>
      <h2>{props.children}</h2>
    </>
  );
}

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

export default ChildCom;
JavaScript
import ChildCom from './components/ChildCom';

function App() {
  return (
    <div className="App">
      {/* Warning: Failed prop type: Invalid prop `children` of type `array` supplied to `ChildCom`, expected a single ReactElement. */}
      <ChildCom>
        <span>插槽</span>
        <span>插槽</span>
      </ChildCom>
      {/* ✅ */}
      <ChildCom>
        <span>插槽</span>
      </ChildCom>
      {/* Warning: Failed prop type: Invalid prop `children` of type `string` supplied to `ChildCom`, expected a single ReactElement. */}
      <ChildCom>插槽</ChildCom>
    </div>
  );
}

export default App;

书写默认值

JSX
import React from 'react';

function ChildCom(props) {
  return (
    <>
      <h1>这里是一个子组件</h1>
      <h2>{props.name}</h2>
    </>
  );
}

ChildCom.defaultProps = {
  name: '默认值'
};

export default ChildCom;
JavaScript
import ChildCom from './components/ChildCom';

function App() {
  return (
    <div className="App">
      <ChildCom />
      <ChildCom name="custom name" />
    </div>
  );
}

export default App;

警告

现在官方提倡用 JavaScript 的默认值语法,而不是 defaultProps,这个用法将在不久之后废弃掉。