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でエラーが表示される。
かなりいい感じ〜