React有很多使用props 类型判断props 值的方法.我常用的一个是React.PropTypes.shape({...}).然而,我最近遇到了一种情况,我有一个对象,其中将包含动态键/值.我知道每个键都应该是一个字符串(以已知的格式),每个值都应该是一个int.即使使用自定义的props 验证函数,它仍然假设您知道props 的键.如何使用PropTypes判断对象/形状的键和值是否正确?

...
someArray: React.PropTypes.arrayOf(React.PropTypes.shape({
  // How to specify a dynamic string key? Keys are a date/datetime string
  <dynamicStringKey>: React.PropTypes.number
}))
...

所以再说一遍:我想至少判断每个键的值是否是一个数字.理想情况下,我还希望能够判断密钥本身是否是正确格式的字符串.

推荐答案

Note:这个答案写于2015年,当时React的当前版本为0.14.3.它可能适用于您今天使用的React版本,也可能不适用.

这是一个有趣的问题.从你的问题来看,你似乎

// You can also specify a custom validator. It should return an Error
// object if the validation fails. Don't `console.warn` or throw, as this
// won't work inside `oneOfType`.
customProp: function(props, propName, componentName) {
  if (!/matchme/.test(props[propName])) {
    return new Error('Validation failed!');
  }
}

在实现类型判断器时,我更喜欢使用React的内置类型

类型判断器的工作原理

下面是类型判断器的函数签名:

function(props, propName, componentName, location, propFullName) => null | Error

如您所见,所有的props 都作为第一个参数传递,并且

有了这些知识,我们现在可以直接调用类型判断器:

PropTypes.number({ myProp: 'bad' }, 'myProp');
// => [Error: Invalid undefined `myProp` of type `string` supplied
//     to `<<anonymous>>`, expected `number`.]

看见如果没有所有的论据,就没那么有用了.这样更好:

PropTypes.number({ myProp: 'bad' }, 'myProp', 'MyComponent', 'prop')
// => [Error: Invalid prop `myProp` of type `string` supplied
//     to `MyComponent`, expected `number`.]

数组类型判断器

文档中没有提到的一点是,当您提供自定义类型时

function validArrayItem(arr, idx, componentName, location, propFullName) {
  var obj = arr[idx];

  console.log(propFullName, obj);

  // 1. Check if `obj` is an Object using `PropTypes.object`
  // 2.判断其所有键是否符合指定的格式
  // 3.判断其所有值是否都是数字

  return null;
}

到目前为止,它总是返回null(这表示有效的props ),但我们

var typeChecker = PropTypes.arrayOf(validArrayItem);
var myArray = [ { foo: 1 }, { bar: 'qux' } ];
var props = { myProp: myArray };

typeChecker(props, 'myProp', 'MyComponent', 'prop');
// -> myProp[0] { foo: 1 }
//    myProp[1] { bar: 'qux' }
// => null

如你所见,第一项propFullName等于myProp[0]

现在让我们充实一下函数的三个部分.

1. Check if obj is an Object using PropTypes.object

这是最简单的部分:

function validArrayItem(arr, idx, componentName, location, propFullName) {
  var obj = arr[idx];
  var props = {};
  props[propFullName] = obj;

  // Check if `obj` is an Object using `PropTypes.object`
  var isObjectError = PropTypes.object(props, propFullName, componentName, location);
  if (isObjectError) { return isObjectError; }

  return null;
}

var typeChecker = PropTypes.arrayOf(validArrayItem);
var props = { myProp: [ { foo: 1 }, 'bar' ] };
typeChecker(props, 'myProp', 'MyComponent', 'prop');
// => [Error: Invalid prop `myProp[1]` of type `string` supplied to
//     `MyComponent`, expected `object`.]

完美的下一个

2.判断其所有键是否符合指定的格式

在你的问题中,你说"每个键都应该是一个字符串",但所有的键都是对象

var STARTS_WITH_UPPERCASE_LETTER_EXPR = /^[A-Z]/;

function validObjectKeys(props, propName, componentName, location, propFullName) {
  var obj = props[propName];
  var keys = Object.keys(obj);

  // If the object is empty, consider it valid
  if (keys.length === 0) { return null; }

  var key;
  var propFullNameWithKey;

  for (var i = 0; i < keys.length; i++) {
    key = keys[i];
    propFullNameWithKey = (propFullName || propName) + '.' + key;

    if (STARTS_WITH_UPPERCASE_LETTER_EXPR.test(key)) { continue; }

    return new Error(
      'Invalid key `' + propFullNameWithKey + '` supplied to ' +
      '`' + componentName + '`; expected to match ' +
      STARTS_WITH_UPPERCASE_LETTER_EXPR + '.'
    );
  }

  return null;
}

我们可以自行测试:

var props = { myProp: { Foo: 1, bar: 2 } };
validObjectKeys(props, 'myProp', 'MyComponent', 'prop');
// -> myProp.Foo Foo
//    myProp.bar bar
// => [Error: Invalid key `myProp.bar` supplied to `MyComponent`;
//     expected to match /^[A-Z]/.]

太棒了让我们将其集成到我们的validArrayItem型判断器中:

function validArrayItem(arr, idx, componentName, location, propFullName) {
  var obj = arr[idx];
  var props = {};
  props[propFullName] = obj;

  // Check if `obj` is an Object using `PropTypes.object`
  var isObjectError = PropTypes.object(props, propFullName, componentName, location);
  if (isObjectError) { return isObjectError; }

  // Check if all of its keys conform to some specified format
  var validObjectKeysError = validObjectKeys(props, propFullName, componentName);
  if (validObjectKeysError) { return validObjectKeysError; }

  return null;
}

并进行测试:

var props = { myProp: [ { Foo: 1 }, { bar: 2 } ] };
var typeChecker = PropTypes.arrayOf(validArrayItem);
typeChecker(props, 'myProp', 'MyComponent', 'prop');
// -> myProp[0].Foo Foo
//    myProp[1].bar bar
// => [Error: Invalid key `myProp[1].bar` supplied to `MyComponent`;
//     expected to match /^[A-Z]/.]

最后...

3.判断其所有值是否都是数字

幸运的是,我们不需要在这里做太多工作,因为我们可以使用

// Check if all of its values are numbers
var validObjectValues = PropTypes.objectOf(PropTypes.number);
var validObjectValuesError = validObjectValues(props, propFullName, componentName, location);
if (validObjectValuesError) { return validObjectValuesError; }

我们将在下面进行测试.

现在一起

以下是我们的最终代码:

function validArrayItem(arr, idx, componentName, location, propFullName) {
  var obj = arr[idx];
  var props = {};
  props[propFullName] = obj;

  // Check if `obj` is an Object using `PropTypes.object`
  var isObjectError = PropTypes.object(props, propFullName, componentName, location);
  if (isObjectError) { return isObjectError; }

  // Check if all of its keys conform to some specified format
  var validObjectKeysError = validObjectKeys(props, propFullName, componentName);
  if (validObjectKeysError) { return validObjectKeysError; }

  // Check if all of its values are numbers
  var validObjectValues = PropTypes.objectOf(PropTypes.number);
  var validObjectValuesError = validObjectValues(props, propFullName, componentName, location);
  if (validObjectValuesError) { return validObjectValuesError; }

  return null;
}

我们将编写一个快速方便的函数进行测试,并抛出一些数据

function test(arrayToTest) {
  var typeChecker = PropTypes.arrayOf(validArrayItem);
  var props = { testProp: arrayToTest };
  return typeChecker(props, 'testProp', 'MyComponent', 'prop');
}

test([ { Foo: 1 }, { Bar: 2 } ]);
// => null

test([ { Foo: 1 }, { bar: 2 } ]);
// => [Error: Invalid key `testProp[1].bar` supplied to `MyComponent`;
//     expected to match /^[A-Z]/.]

test([ { Foo: 1 }, { Bar: false } ]);
// => [Error: Invalid prop `testProp[1].Bar` of type `boolean` supplied to
//     `MyComponent`, expected `number`.]

真管用!现在,您可以在React组件中使用它,就像

MyComponent.propTypes = {
  someArray: PropTypes.arrayOf(validArrayItem);
};

当然,我会建议给它起个更有意义的名字,然后搬家

Reactjs相关问答推荐

如何在MUI X数据网格列中显示IMG?

关于同一位置的不同组件实例的react S规则被视为相同组件

面对动画警告:未指定`useNativeDriver`.这是必需的选项,并且必须在REACT本机中显式设置为`true`或`False`

这两个子元素在Reaction Native中使用的有什么不同?

React,当我调用handleSubmit()函数时,我正在将application/json和multiform/data中的数据发送到后端,但student_image中没有数据:null

如何垂直对齐 React Bootstrap Table 行中的项目

在react的useEffect钩子中,我的函数被调用,但只有第一个函数能够改变状态,第二个函数无法改变状态.

如何在 JS 中绘制具有不同笔画宽度的样条线

无法设置 null 的属性(设置src)

使用状态与复选框不同步

如何通过 id 从 useSprings 数组中删除元素

react 事件顺序

使用输入类型文本对 useState 和日期做出react

如何使用react 路由将 url 参数限制为一组特定的值?

将 Material UI 菜单渲染为

使用 React 中的功能组件更改另一个组件的状态

组件焦点上的 MUI 更改栏 colored颜色

React如何在用户登录后等待当前用户数据被获取

CORS 政策:无访问控制允许来源-AWS 和 Vercel

为什么我从另一个组件收到错误?