動的なキーを持つオブジェクトのPropTypesチェック
質問
Reactには、PropTypesを使ってpropの値をチェックする方法がたくさんあります。私がよく使うのは
React.PropTypes.shape({...})
. しかし、私は最近、内部に動的なキー/値を持つオブジェクトを持っている状況に出くわしました。各キーは文字列 (既知の形式) であるべきで、各値は int であるべきであることは分かっています。カスタムのプロップ検証関数を使っても、プロップのキーを知っていることを前提にしています。オブジェクト/図形のキーと値の両方が正しいことをチェックするためにPropTypesを使用するにはどうすればよいですか?
...
someArray: React.PropTypes.arrayOf(React.PropTypes.shape({
// How to specify a dynamic string key? Keys are a date/datetime string
<dynamicStringKey>: React.PropTypes.number
}))
...
そこでもう一度。少なくとも、各キーの値が数値であることをチェックしたい。理想を言えば、キー自体が正しい形式の文字列であることもチェックできればと思います。
どのように解決するのですか?
注意 : この回答は2015年に書かれたもので、現在のReactのバージョンは0.14.3です。あなたが今使っているReactのバージョンに当てはまるかもしれませんし、当てはまらないかもしれません。
それは興味深い質問ですね。あなたの質問から、あなたは次のように聞こえました。 のドキュメントでカスタムタイプチェッカーについて読んだようです。 Prop Validation (提案の検証) . 後世のために、ここに再現しておきます。
// 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!'); } }
タイプチェッカーを実装する場合、私はできるだけReactの組み込み型
チェッカーを実装する場合、私はできるだけReactの組み込み型チェッカーを使いたいと思っています。値が
であるかどうかをチェックしたいので
PropTypes.number
を使うべきでしょう?でも
を使えばいいんです。
PropTypes.number('not a number!')
を実行するだけで
を実行し、適切なエラーを得ることができればよいのですが、残念ながらそれは
です。まず最初に理解すべきは...
タイプチェッカーの仕組み
タイプチェッカーの関数シグネチャは以下の通りです。
function(props, propName, componentName, location, propFullName) => null | Error
ご覧のとおり、すべてのプロップが第1引数として渡され、第2引数として
テストするプロップの名前が第2引数として渡されます。最後の
最後の3つの引数は、有用なエラーメッセージを出力するために使われます。
は任意です。
componentName
は自明である。
location
のいずれかになります。
'prop'
,
'context'
または
'childContext'
(私たちは
'prop'
にのみ興味があります)、そして
propFullName
はネストした
小道具を扱うときのものです。
someObj.someKey
.
この知識を持って、型チェッカを直接呼び出すことができるようになりました。
PropTypes.number({ myProp: 'bad' }, 'myProp');
// => [Error: Invalid undefined `myProp` of type `string` supplied
// to `<<anonymous>>`, expected `number`.]
ほらね。すべての引数がないと、それほど便利ではありません。これはより良いです。
PropTypes.number({ myProp: 'bad' }, 'myProp', 'MyComponent', 'prop')
// => [Error: Invalid prop `myProp` of type `string` supplied
// to `MyComponent`, expected `number`.]
配列の型チェッカー
ドキュメントに書かれていないことのひとつに、カスタムタイプ
チェッカを
PropTypes.arrayOf
にカスタム型チェッカーを提供する場合、 それは各配列
の各要素に対して呼び出され、最初の二つの引数はそれぞれ配列そのものと
はそれぞれ現在の要素のインデックスとなります。これで、型チェッカのスケッチを始めることができます。
型チェッカのスケッチを始めることができます。
function validArrayItem(arr, idx, componentName, location, propFullName) {
var obj = arr[idx];
console.log(propFullName, obj);
// 1. Check if `obj` is an Object using `PropTypes.object`
// 2. Check if all of its keys conform to some specified format
// 3. Check if all of its values are numbers
return null;
}
これまでのところ、それは常に
null
(を返します(これは有効なプロップを示します)。
を投げ入れました。
console.log
を挿入して、何が起こっているのか覗いてみました。 これで
このようにテストできます。
var typeChecker = PropTypes.arrayOf(validArrayItem);
var myArray = [ { foo: 1 }, { bar: 'qux' } ];
var props = { myProp: myArray };
typeChecker(props, 'myProp', 'MyComponent', 'prop');
// -> myProp[0] { foo: 1 }
// myProp[1] { bar: 'qux' }
// => null
ご覧のように
propFullName
は
myProp[0]
であり、最初の項目は
myProp[1]
である。
では、関数の3つの部分を肉付けしてみましょう。
1. チェックするのは
obj
がオブジェクトであるかどうかを
PropTypes.object
これは最も簡単な部分です。
function validArrayItem(arr, idx, componentName, location, propFullName) {
var obj = arr[idx];
var props = {};
props[propFullName] = obj;
// Check if `obj` is an Object using `PropTypes.object`
var isObjectError = PropTypes.object(props, propFullName, componentName, location);
if (isObjectError) { return isObjectError; }
return null;
}
var typeChecker = PropTypes.arrayOf(validArrayItem);
var props = { myProp: [ { foo: 1 }, 'bar' ] };
typeChecker(props, 'myProp', 'MyComponent', 'prop');
// => [Error: Invalid prop `myProp[1]` of type `string` supplied to
// `MyComponent`, expected `object`.]
完璧だ!次は...
2. そのキーのすべてがある特定のフォーマットに適合しているかどうかをチェックする
質問の中で、「各キーは文字列であるべきだ」とありますが、JavaScriptのすべてのオブジェクトのキーは文字列です。 JavaScript のすべてのオブジェクトのキーは文字列です。 キーがすべて大文字で始まるかどうかをテストしたいとします。そのためのカスタム タイプチェッカーを作りましょう。
var STARTS_WITH_UPPERCASE_LETTER_EXPR = /^[A-Z]/;
function validObjectKeys(props, propName, componentName, location, propFullName) {
var obj = props[propName];
var keys = Object.keys(obj);
// If the object is empty, consider it valid
if (keys.length === 0) { return null; }
var key;
var propFullNameWithKey;
for (var i = 0; i < keys.length; i++) {
key = keys[i];
propFullNameWithKey = (propFullName || propName) + '.' + key;
if (STARTS_WITH_UPPERCASE_LETTER_EXPR.test(key)) { continue; }
return new Error(
'Invalid key `' + propFullNameWithKey + '` supplied to ' +
'`' + componentName + '`; expected to match ' +
STARTS_WITH_UPPERCASE_LETTER_EXPR + '.'
);
}
return null;
}
単体でテストできる
var props = { myProp: { Foo: 1, bar: 2 } };
validObjectKeys(props, 'myProp', 'MyComponent', 'prop');
// -> myProp.Foo Foo
// myProp.bar bar
// => [Error: Invalid key `myProp.bar` supplied to `MyComponent`;
// expected to match /^[A-Z]/.]
素晴らしい! これを私たちの
validArrayItem
タイプチェッカーに統合してみましょう。
function validArrayItem(arr, idx, componentName, location, propFullName) {
var obj = arr[idx];
var props = {};
props[propFullName] = obj;
// Check if `obj` is an Object using `PropTypes.object`
var isObjectError = PropTypes.object(props, propFullName, componentName, location);
if (isObjectError) { return isObjectError; }
// Check if all of its keys conform to some specified format
var validObjectKeysError = validObjectKeys(props, propFullName, componentName);
if (validObjectKeysError) { return validObjectKeysError; }
return null;
}
そしてテストしてみてください。
var props = { myProp: [ { Foo: 1 }, { bar: 2 } ] };
var typeChecker = PropTypes.arrayOf(validArrayItem);
typeChecker(props, 'myProp', 'MyComponent', 'prop');
// -> myProp[0].Foo Foo
// myProp[1].bar bar
// => [Error: Invalid key `myProp[1].bar` supplied to `MyComponent`;
// expected to match /^[A-Z]/.]
そして最後に...
3. その値がすべて数字であるかどうかをチェックする
幸いなことに、ここで多くの作業をする必要はありません。
組み込みの
PropTypes.objectOf
:
// Check if all of its values are numbers
var validObjectValues = PropTypes.objectOf(PropTypes.number);
var validObjectValuesError = validObjectValues(props, propFullName, componentName, location);
if (validObjectValuesError) { return validObjectValuesError; }
以下、テストしてみます。
今すぐ全員集合
これが最終的なコードです。
function validArrayItem(arr, idx, componentName, location, propFullName) {
var obj = arr[idx];
var props = {};
props[propFullName] = obj;
// Check if `obj` is an Object using `PropTypes.object`
var isObjectError = PropTypes.object(props, propFullName, componentName, location);
if (isObjectError) { return isObjectError; }
// Check if all of its keys conform to some specified format
var validObjectKeysError = validObjectKeys(props, propFullName, componentName);
if (validObjectKeysError) { return validObjectKeysError; }
// Check if all of its values are numbers
var validObjectValues = PropTypes.objectOf(PropTypes.number);
var validObjectValuesError = validObjectValues(props, propFullName, componentName, location);
if (validObjectValuesError) { return validObjectValuesError; }
return null;
}
テスト用に簡単な関数を書いて、いくつかのデータを投げてみましょう。 を投げてみましょう。
function test(arrayToTest) {
var typeChecker = PropTypes.arrayOf(validArrayItem);
var props = { testProp: arrayToTest };
return typeChecker(props, 'testProp', 'MyComponent', 'prop');
}
test([ { Foo: 1 }, { Bar: 2 } ]);
// => null
test([ { Foo: 1 }, { bar: 2 } ]);
// => [Error: Invalid key `testProp[1].bar` supplied to `MyComponent`;
// expected to match /^[A-Z]/.]
test([ { Foo: 1 }, { Bar: false } ]);
// => [Error: Invalid prop `testProp[1].Bar` of type `boolean` supplied to
// `MyComponent`, expected `number`.]
うまくいきましたね。これで、Reactコンポーネントでも 内蔵のタイプチェッカーと同じように
MyComponent.propTypes = {
someArray: PropTypes.arrayOf(validArrayItem);
};
もちろん、もっと意味のある名前を付けて、独自のモジュールに移動することをお勧めします。 を独自のモジュールにすることをお勧めします。
関連
-
[解決済み】React.jsの配列の子要素のユニークキーを理解する
-
[解決済み】Reactでclsxを使用する方法
-
[解決済み] FontAwesomeの無料パッケージに含まれているアイコンのオブジェクト名はどこにあるのですか?
-
[解決済み] React JS Jestで「SyntaxError: 予期しないトークン"
-
[解決済み] Error: yarn start - エラー コマンド "start" が見つかりません。
-
[解決済み] AxiosにCORSの問題が発生
-
[解決済み] React Hooksの「exhaustive-deps」lintルールを理解する
-
[解決済み] reactのuseStateフックでコールバックを使う方法 [重複]。
-
[解決済み] React」は定義される前に使用されていた
-
[解決済み】ReactのPropTypes。1つのプロップに対して異なるタイプのPropTypesを許可する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Reactを使用したMapBoxのCSSが欠落している件
-
[解決済み] テスト
-
[解決済み】プリセットファイルはオブジェクトのエクスポートができない
-
[解決済み] Jestの `beforeEach` グローバルは何のためにあるのですか?
-
[解決済み] error 'document' is not defined : eslint / React
-
[解決済み] ReactJS giving error Uncaught TypeError: Super expression は null か関数でなければならず、undefined ではありません。
-
[解決済み] React-Router 4 キャッチオールルート
-
[解決済み] 'Proptypes'が定義されていない
-
[解決済み] React JS Jestで「SyntaxError: 予期しないトークン"
-
[解決済み] Error: yarn start - エラー コマンド "start" が見つかりません。