【问题标题】:Multiple validations on React PropTypesReact PropTypes 的多重验证
【发布时间】:2015-09-18 22:15:12
【问题描述】:

有没有办法使用React.PropTypes 对单个道具进行多次验证。特别想混合自定义验证和库存验证。

我有两个道具,一个对象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')

有没有办法使用内置的验证器来实现这个工作,或者在我的函数中重写它是唯一的选择吗?

【问题讨论】:

    标签: javascript reactjs coffeescript react-proptypes


    【解决方案1】:

    来自文档中的Reusable Components 页面:

    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”函数,它接受两个 propType 并合并结果。

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

    然后您可以使用它来针对多个 propType 进行断言。

    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.PropTypes.string.isRequired),因为它对正在发生的事情更加明显跨度>
    • @PhilVarg 您需要创建自己的道具类型。据我所知,没有一个内置的 propTypes 做任何交叉道具检查。您可以将它放在某个模块中并以一个好听的名称导入它,甚至可以让options 部分是动态的,例如foo: isKeyOfProp('options').
    【解决方案2】:

    如果您关注this 链接,Ian Thomas 解释了 createChainableTypeChecker 方法的使用,该方法在 react 中但不作为 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?
    猜你喜欢
    • 2020-10-29
    • 2018-01-25
    • 2018-01-14
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-04
    相关资源
    最近更新 更多