Множественные проверки React PropTypes

Есть ли способ провести несколько проверок одной опоры, используя 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')

Есть ли способ заставить это работать, используя реакции, встроенные в валидатор, или единственный вариант переписать его в моей функции?


person PhilVarg    schedule 01.07.2015    source источник


Ответы (2)


На странице Повторно используемые компоненты в документации:

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

Затем вы можете использовать это, чтобы утверждать против нескольких 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(', ')})`
        )
  )
}

Примечание: ничего из этого не проверено, но нет синтаксических ошибок! Вы можете скомпилировать его в es3 с помощью babel или конвертировать в CS вручную.

person Brigand    schedule 01.07.2015
comment
Я знаю, что могу просто продолжать добавлять вещи в свою пользовательскую проверку. это, вероятно, могло бы обойтись, выполнив return new Error('msg') unless typeof props[propName] == 'string', но я спрашиваю, есть ли более формальный способ, который обеспечивает реакция (т.е. все еще возможность использовать React.PropTypes.string.isRequired), потому что это гораздо более очевидно в отношении того, что происходит - person PhilVarg; 01.07.2015
comment
@PhilVarg вам нужно создать свой собственный тип. Насколько я знаю, ни один из встроенных propTypes не выполняет перекрестных проверок. Вы можете поместить его куда-нибудь в модуль и импортировать с красивым именем, и даже часть options будет динамической, например. foo: isKeyOfProp('options'). - person Brigand; 02.07.2015

Если вы перейдете по этой ссылке, Ян Томас объяснит использование метод 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;
}
person Churchill    schedule 26.08.2015
comment
Где я могу получить ReactPropTypeLocationNames? - person Shanimal; 31.03.2017