2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Custom PropTypes Validator

Last updated at Posted at 2017-06-28

prop-typesが提供しているものでも十分だが、もっと細かいTypecheckingが必要な場合がある。
custom validatorを作ってみよう。

custom validatorを作るための原則

  • validatorはpropertyのリスト、検証したいproperty名、コンポーネント名を引数として持つ関数だ。
  • validatorは検証したpropertyが有効な場合は何も返さないが、間違った場合はErrorのインスタンスを返さなければならない。

今度作りたいcustom validatorは

propertyが必須で、値が文字列である。
文字列の長さは80文字以内でなければならない。

const customPropType = (props, propName, componentName) => {
  if (props[propName]) {
    const value = props[propName];
    if (typeof value !== 'string' || value.lenght > 80) {
      return new Error(
        `${propName} in ${componentName} is longer than 80 characters`,
      )
    }
  }
};

動作には問題ないが、eslintエラーが出る。

propType "title" is not required, but has no corresponding defaultProp declaration. (react/require-default-props)

そもそも検証の対象になるpropertyは必須だった。
isRequiredを付けるか、defaultPropで指定しないと解決できない。
isRequiredを付けると、eslintエラーは消えたが、browserのほうでエラーが表示された。
custom validatorを作る場合は、isRequiredについても別途に実装しなければならないようだ。
Reactのガイドにはcustom validatorについて上記のような一般的な例を紹介しているだけで、isRequiredは言及されてない。

同じ悩みを持っている人はどこにもいる。
案外に重要な話だ。すぐ解決できない場合はぐぐってみよう。
ぐぐっても解決できない場合は、githubのissuesやwikiとかで探してみよう。(stackoverflowよりマシだ。)
次はreactのgithub issuesから見つけたものだ。
結構よかったので、紹介する。

// This is a factory function (also called a higher-order function)
function createCustomPropType(isRequired) {
  // The factory returns a custom prop type
  return function(props, propName, componentName) {
    const prop = props[propName];
    if (prop == null) {
      // Prop is missing
      if (isRequired) {
        // Prop is required but wasn't specified. Throw an error.
        throw new Error();
      }
      // Prop is optional. Do nothing.
    } else {
      // Put your validation logic here...
    }
  }
}

// Using the factory, create two different versions of your prop type
const customPropType = createCustomPropType(false);
customPropType.isRequired = createCustomPropType(true);

// Now this will work:
MyComponent.propTypes = {
  optional: customPropType,
  required: customPropType.isRequired,
};

custom validatorとして、factory functionを作っている。
propertyが必須なので、optionalは意味がない。
注目するのはrequiredのところだ。
早速、必要なvalidationを入れて確認した。
動作には問題ない。
しかし、いくつかeslintエラーが出たので次のように修正した。

function createCustomPropType(isRequired) {
  return (props, propName, componentName) => {
    const prop = props[propName];
    if (prop == null) {
      if (isRequired) {
        return new Error(
          `The prop \`${propName}\` is marked as required in \`${componentName}\`, but its value is \`undefined\`.`,
        );
      }
    } else if (typeof prop !== 'string' || prop.length > 80) {
      return new Error(
        `${propName} in ${componentName} is longer than 80 characters`,
      );
    }
    return null;
  };
}

const customPropType = createCustomPropType(false);
customPropType.isRequired = createCustomPropType(true);

MyComponent.propTypes = {
  required: customPropType.isRequired,
};

検証しているpropertyが文字列ではない場合、そして文字列の長さが80を超えるとbrowserでエラーが表示される。
isRequiredを付けた場合は、該当propertyが存在しないとbrowserでエラーが表示される。
かなりいい感じ〜:thumbsup:

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?