React PropTypes的多重验证

7

有没有一种方法可以使用React.PropTypes在单个属性上进行多次验证。特别是想要混合自定义验证和库验证。

我有两个props,一个对象options和一个字符串value。我想检查props.value是否是一个字符串,但也是对象上的一个键。使用coffeescript,它看起来像:

propTypes:
  options: React.PropTypes.Object.isRequired
  value: (props, propName, componentName) ->
    unless props[propName] of props.options
      new Error('my custom message')

这很好用,但我还想确保我的值是字符串类型。我确定我可以在自定义函数中手动添加验证,但理想情况下,我只想使用 React.PropTypes.string.isRequired。我尝试了将其放入自定义函数并执行,但没有起作用。以下方法也不行:
  value: React.PropTypes.string.isRequired && (props, propName, componentName) ->
    unless props[propName] of props.options
      new Error('my custom message')

有没有使用React内置验证器使其工作的方法,或者在我的函数中重新编写是唯一的选择?

2个回答

3

从文档中的可重用组件页面:

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!');
  }
}

propType 可以返回空或错误对象。我们可以编写一个“all”函数,将两个 propTypes 合并在一起。

const allPropTypes = (...types) => (...args) => {
  const errors = types.map((type) => type(...args)).filter(Boolean);

  // no errors? cool!
  if (errors.length === 0) return;

  // collect the messages and join them together
  const message = errors.map((e) => e.message).join('\n');
  return new Error(message);
};

然后,您可以使用此功能来针对多个propTypes进行断言。
propTypes = {
  foo: allPropTypes(
    PropTypes.string.isRequired,
    (props, propName, componentName) => props.options && props.options[props[propName]] 
      ? undefined
      : new Error(
          `${componentName}: expected prop ${propName}="${prop[propName]}"` 
          + `to be a key of prop "options" `
          + `(one of ${Object.keys(props.options).join(', ')})`
        )
  )
}

注意:这些代码没有经过测试,但是没有语法错误!你可以使用babel将其编译为es3,或者手动将其转换为CS。

我知道我可以继续添加自定义验证规则。通过执行return new Error('msg') unless typeof props[propName] == 'string',可能可以实现,但我想问一下React是否提供了更正式的方式(例如仍然能够使用React.PropTypes.string.isRequired),因为这样更容易理解正在发生的事情。 - PhilVarg
@PhilVarg,你需要创建自己的proptype。据我所知,没有任何内置的propTypes进行任何跨属性检查。您可以将其放在某个模块中并使用漂亮的名称导入它,甚至可以使“options”部分是动态的,例如foo: isKeyOfProp('options') - Brigand

0
如果你点击this链接,Ian Thomas会解释在React中使用createChainableTypeChecker方法的用途,该方法不作为propTypes模块的一部分导出。这篇文章清晰地解释了如何使用相同的代码来链接验证调用:
function createChainableTypeChecker(validate) {  
  function checkType(isRequired, props, propName, componentName, location) {
    componentName = componentName || ANONYMOUS;
    if (props[propName] == null) {
      var locationName = ReactPropTypeLocationNames[location];
      if (isRequired) {
        return new Error(
          ("Required " + locationName + " `" + propName + "` was not specified in ") +
          ("`" + componentName + "`.")
        );
      }
      return null;
    } else {
      return validate(props, propName, componentName, location);
    }
  }

  var chainedCheckType = checkType.bind(null, false);
  chainedCheckType.isRequired = checkType.bind(null, true);

  return chainedCheckType;
}

我在哪里可以获取ReactPropTypeLocationNames? - Shanimal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接