react proptypes node reactjs

reactjs - node - react proptypes install



Comprobación PropTypes del objeto con claves dinámicas (3)

React tiene muchas formas de usar PropTypes para verificar el valor de un accesorio. Uno que uso comúnmente es React.PropTypes.shape({...}) . Sin embargo, recientemente encontré una situación en la que tengo un objeto que tendrá clave / valores dinámicos en el interior. Sé que cada clave debe ser una cadena (en un formato conocido), y cada valor debe ser un int. Incluso utilizando una función de validación de prop personalizada, aún asume que conoce la clave del puntal. ¿Cómo uso PropTypes para verificar que las claves y los valores de un objeto / forma sean correctos?

... someArray: React.PropTypes.arrayOf(React.PropTypes.shape({ // How to specify a dynamic string key? Keys are a date/datetime string <dynamicStringKey>: React.PropTypes.number })) ...

Entonces otra vez: quiero al menos verificar que el valor de cada clave sea un número. Idealmente, también me gustaría poder verificar que la clave en sí misma sea una cadena en el formato correcto.


Esa es una pregunta interesante. De su pregunta, parece que ha leído acerca de las comprobaciones de tipo personalizadas en los documentos para Validación de Prop . Para la posteridad lo reproduciré aquí:

// 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!''); } }

Al implementar las comprobaciones de tipo, prefiero usar las comprobaciones de tipo incorporadas de React tanto como sea posible. Desea verificar si los valores son números, entonces deberíamos usar PropTypes.number para eso, ¿verdad? Sería bueno si pudiéramos hacer PropTypes.number(''not a number!'') Y obtener el error apropiado, pero desafortunadamente es un poco más complicado que eso. La primera parada es entender ...

Cómo funcionan las fichas de tipo

Aquí está la firma de la función de un verificador de tipos:

function(props, propName, componentName, location, propFullName) => null | Error

Como puede ver, todos los accesorios se pasan como el primer argumento y el nombre del accesorio que se prueba se pasa como el segundo. Los últimos tres argumentos se utilizan para imprimir mensajes de error útiles y son opcionales: componentName es autoexplicativo. location será una de ''prop'' , ''context'' o ''childContext'' (solo estamos interesados ​​en ''prop'' ), y propFullName es para cuando se trata de accesorios anidados, por ejemplo, someObj.someKey .

Armados con este conocimiento, ahora podemos invocar un verificador de tipos directamente:

PropTypes.number({ myProp: ''bad'' }, ''myProp''); // => [Error: Invalid undefined `myProp` of type `string` supplied // to `<<anonymous>>`, expected `number`.]

¿Ver? No es tan útil sin todos los argumentos. Esta es mejor:

PropTypes.number({ myProp: ''bad'' }, ''myProp'', ''MyComponent'', ''prop'') // => [Error: Invalid prop `myProp` of type `string` supplied // to `MyComponent`, expected `number`.]

Un verificador de tipo de matriz

Una cosa que los documentos no mencionan es que cuando se proporciona un comprobador de tipos personalizado a PropTypes.arrayOf , se llamará para cada elemento de la matriz, y los dos primeros argumentos serán la matriz misma y el índice del elemento actual, respectivamente. Ahora podemos comenzar a esbozar nuestro verificador de tipos:

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

Hasta ahora siempre devolverá null (lo que indica accesorios válidos), pero lanzamos un console.log para echar un vistazo a lo que está sucediendo. Ahora podemos probarlo así:

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

Como puede ver, propFullName es myProp[0] para el primer elemento y myProp[1] para el segundo.

Ahora desarrollemos las tres partes de la función.

1. Compruebe si obj es un Objeto usando PropTypes.object

Esta es la parte más fácil:

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`.]

¡Perfecto! Siguiente...

2. Compruebe si todas sus claves se ajustan a algún formato especificado

En su pregunta, dice "cada clave debe ser una cadena", pero todas las claves de objeto en JavaScript son cadenas, así que digamos, de forma arbitraria, que queremos probar si todas las claves comienzan con una letra mayúscula. Hagamos un comprobador de tipos personalizado para eso:

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

Podemos probarlo solo:

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]/.]

¡Estupendo! Vamos a integrarlo en nuestro validArrayItem tipos de 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; }

Y pruébalo:

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]/.]

Y finalmente...

3. Compruebe si todos sus valores son números

Afortunadamente, no necesitamos hacer mucho trabajo aquí, ya que podemos usar el 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; }

Lo probaremos a continuación.

Todos juntos ahora

Aquí está nuestro código final:

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

Escribiremos una función de conveniencia rápida para probar y arrojar algunos datos sobre ella:

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`.]

¡Funciona! Ahora puede usarlo en su componente React al igual que las comprobaciones de tipo incorporadas:

MyComponent.propTypes = { someArray: PropTypes.arrayOf(validArrayItem); };

Por supuesto, recomendaría darle un nombre más significativo y moverlo a su propio módulo.


Puede crear su propio validador pasando una función.

Vea customProp aquí .

Creo que puedes hacer algo como React.PropTypes.arrayOf(customValidator) .

Aquí está el validador que está buscando:

function objectWithNumericKeys(obj) { if (Object.keys(obj).some(key => isNaN(key))) return new Error(''Validation failed!''); }


Para validar solo los valores, puede usar React.PropTypes.objectOf .

... someArray: React.PropTypes.arrayOf( React.PropTypes.objectOf(React.PropTypes.number) ) ...