React — Comprobando el tipo de dato de una prop con PropTypes
Temario
- Introducción.
- ¿Qué es PropType?.
- Validaciones básicas (Tipo de dato, Renderizables, Instancia, Múltiples).
- Validaciones avanzadas (Arreglos, Objetos).
- Validando datos obligatorios.
- Validaciones personalizadas (básico, para arreglos y objetos)
i. PropTypes
Imaginemos que tenemos el componente Profile
, donde va a recibir las siguientes propiedades: name
,age
.
Lo agregamos a la App
, donde esperaríamos los atributos fueran así:
En pantalla:
Hasta aquí parece no hay problema, pero qué pasaría si el usuario o desarrollador manda lo siguiente:
Entonces, en pantalla:
Podemos observar que le mandamos atributos al componente con tipo de valores erróneos, en otros hasta hacen falta datos; y lo peor es que en consola no sale ningún tipo de error o advertencia…¿y ahora?
ii. ¿Qué es PropType
?
PropTypes
, mediante un objeto nos va a permitir agregar validaciones de tipo de dato a las props
, asegurándose que la información recibida sea válida.
Importante
PropTypes
sólo verifica los tipo de dato en el entorno de desarrollo, por motivos de rendimiento no se activa en el entorno de producción.
A partir de la versión 15.5 de React, se volvió un paquete separado llamado prop-types
[ref]. En caso de que estés haciendo una aplicación desde cero, debes de agregar el paquete a tus dependencias[ref]; si tu aplicación la creaste con create-react-app
no es necesario cargarla, ya viene dentro de las dependencias.
:: Sintaxis de PropType
Debemos de importar el paquete y utilizar la sintaxis de arriba, en el componente que vamos a validar:
En el siguiente capítulo vamos a ver cómo se agregan las validaciones.
iii. Validaciones básicas
a — Tipo de dato
:: Tipos
PropTypes.string
: Debe ser una cadena de texto.
PropTypes.number
: Debe ser numérico.
PropTypes.bool
: Debe se un booleano.
PropTypes.func
: Debe ser una función.
Es muy común usarla en los componentes Form
, donde manejamos desde el padre el evento que lanza el hijo.
PropTypes.array
: Debe ser un arreglo.
PropTypes.object
: Debe ser un objeto.
PropTypes.symbol
: Debe ser un símbolo.
PropTypes.any
: Cualquier tipo de dato (veremos un ejemplo más abajo)
:: Ejemplos
Aprovechemos el ejemplo anterior, si aplicamos las reglas, el componente funcional Profile
quedaría de la siguiente manera:
Le estamos indicando que la propiedad name
va a ser de tipo string
y la propiedad age
va a ser de tipo number
, con estas validaciones, la consola nos va a arrojar mensajes de advertencia cuando los atributos mandados al componente no corresponda al tipo de dato que la propiedad espera.
Aumentemos complejidad al componente; imaginemos que vamos a mostrar el perfil de la persona, donde necesitamos los siguientes datos:
- Nombre
name:string
- Edad
age:number
- Pasatiempos
hobbies:array
- Dirección
address:object
Componente Profile
:
Lo agregamos a la App
:
Con este ejemplo, en la aplicación no nos a a mostrar ninguna advertencia, ya que los datos son del tipo correcto.
Vamos a mandarle a la propiedad name
un número:
Podemos observar que SI muestra el componente (inclusive con name = 100
), pero en consola nos arroja la advertencia “Invalid prop name
of type number
supplied to Profile
, expected string
.”
Ver ejemplo (no olvides abrir la consola para ver las advertencias):
Crear las
PropTypes
,de los componentes, sirven como una documentación para el desarrollador que va a ocuparlo, ya que le indica las propiedades que recibe y el tipo de dato.
Con la imagen de arriba, te puedo decir que el componente Profile
acepta las propiedades name:string, age:number, address:object, hobbies:array.
b — Renderizables
PropTypes
, también hace validaciones a los componentes o elementos garantizando que React los pueda representar.
:: Tipos
PropTypes.node
: Debe ser cualquier cosa que React pueda interpretar : número, cadena, elemento o arreglo.
Este llega a generar confusión con el PropTypes.any
, pueden sonar a que son lo mismo, pero realmente no, veamos a detalle cada uno:
— PropTypes.node
: Todo aquello que pueda ser representado en pantalla por React, entonces antes de usarlo debemos hacer la pregunta : ¿Se puede ver en pantalla el tipo de dato “n”?
Si son posibles:
No son posibles:
El objeto, sí muestra name
, por que en el componente esta propNode.name
, pero si ponemos directamente propNode
, se rompe toda la aplicación.
El NaN
parece que sí lo acepta, pero te hace la sugerencia de que conviertas el valor a string
.
El tipo PropTypes.node
, es muy común utilizarlo cuando queremos dar la posibilidad de que nos pasen un componente o la clase de CSS del mismo:
— PropTypes.any
: Puede ser cualquier cosa…
Todos ha pasado sin problemas, los mensajes de alerta que salen, el primero, es por que estoy intentando poner en pantalla una función (lo cual no debería), y el segundo es la sugerencia del NaN
, entonces, ninguno de los dos errores son de validación de tipo de dato.
PropTypes.element
: Debe ser un elemento React.
Sabemos que Babel compila JSX a llamadas de React.createElement()
. Esto quiere decir que estos dos ejemplos son exactamente lo mismo:
React.createElement()
internamente genera un objeto, ese objeto generado se le conoce como “Elementos de React”, que son descripciones de lo que queremos ver en pantalla (tipo, propiedades, color, etc), donde, React va a leer este objeto para construir el DOM y mantenerlo actualizado.
Entonces cuando pensemos en un elemento en react, debe ser como un objeto que tiene type, props, key, etc...
, todos estos son elementos válidos:
Una vez que hemos comprendido el concepto de elemento, veamos como funciona PropType.element
.
Inclusive podemos limitar a que el hijo children
solo sea uno:
Sin validación:
Pero cuando agregamos la regla:
Como esta la validación, valida que NO tenga ningún hijo o SOLO uno:
PropTypes.elementType
: Un tipo de elemento React
No debemos de confundirlo con PropType.element
, recordemos que los elementos de React son objetos que van a describir lo que queremos en pantalla.
Admite todos los tipos de componentes (nativos, sin estado, con estado, referencias directas, providers), donde nos va a arrojar una advertencia cuando ninguno de ellos es un elemento, y el tipo de elemento es aquel que aún no tiene un objeto que lo defina como elemento, es un poco complicado de explicar, pero con el siguiente ejemplo, estoy seguro que te va a quedar más claro:
Un punto importante es que los tipos de elementos que estén construidos en React no llevan comillas, ya que internamente React mediante el JSX lo interpreta, mientras que un div
es un componente nativo.
PropTypes.elementType
se agregó a React a partir de la versión 15.7.0 [ref][ref][ref].
Mayormente es utilizado para crear componentes dinámicos, veamos un ejemplo con elementos nativos:
Con el componente de arriba, la idea es pasarle cualquier tipo de elemento nativo y sea capaz de renderizarlo, entonces, la App
quedaría de la siguiente manera:
Ejemplo completo:
Ahora vamos a ver con elementos de React:
Tengo los siguientes componentes:
Entonces en la App
tendríamos lo siguiente:
Ejemplo completo:
PropTypes.elementType
, admite todos los componentes (nativos, sin estado, con estado, referencias directas, provider(context)), en caso de que no sea ninguno de esos elementos arrojará una advertencia, así como también cuando es un elemento y no un tipo.
c — Instancia
:: Tipos
PropTypes.instanceOf
: No solo se limita a los valores primitivos y complejos, también podemos validar si una propiedad pertenece a una instancia de una clase JavaScript. React hace la comparación coninstanceof
que usamos normalmente en JavaScript, por lo cual nos asegura una validación correcta y el mejor rendimiento.
:: Ejemplo
Imagina que tenemos la siguiente clase:
En la aplicación importamos el componente Profile
, que es a quien le pasamos la instancia de la clase User
:
- No olvidemos importar la clase
User
- Hacer la instancia de
User
Ahora, el siguiente paso es validar que la instancia sea la correcta en el componente, por lo que :
- No olvidemos importar la clase
User
(Es obligatorio, si no, no hay forma de validar) - Agregarlo en
Profile.propTypes
Cuando la instancia es correcta, no sale ningún mensaje:
Cuando la instancia no coincide, sale un mensaje de advertencia:
d — Múltiples
:: Tipos
PropTypes.oneOf
: Limitamos la propiedad a un conjunto específico de valores, donde se considera como enum, los valores deben de ir dentro de un arregloPropTypes.oneOf([val1, val2, ...])
, esto quiere decir que si vamos a pasar una propiedad al componente, debe de ser uno de los valores exactos permitidos.
enum: Un tipo de enumeración es un tipo de datos especial que permite que una variable sea un conjunto de constantes predefinidas. La variable debe ser igual a uno de los valores que se han predefinido para ella.
:: Ejemplo
Imaginemos que vamos a mostrar el perfil de la persona, donde necesitamos los siguientes datos:
- Nombre
name:string
- Edad
age:number
- Género
gender:oneOf
, solo debe aceptarFemale, Male
Componente Profile
:
En la App
vamos a mandar, primero atributos correctos:
Cuando nosotros mandamos un valor que no está dentro de los permitidos o no está exactamente escrito, nos arroja una advertencia:
Podemos observar que al primero le mandamos male
en vez de Male
, y en el segundo le estamos mandando Females
cuando solo acepta Female, Male
.
:: Ejemplo 2
Imagina que tenemos el componente Button
, donde solo puede aceptar 3 tipos de botones primary, stroke, flat
:
Y no solo estamos limitados a un solo tipo de valor, podemos mezclar:
PropTypes.oneOfType
: La propiedad debe ser un conjunto específico de tipos de datos.
:: Ejemplo
Imaginemos que tenemos un Layout tipo Bootstrap[ref], Skeleton[ref], personalizado, donde tenemos el componente Container
, donde recibe la propiedad fluid
con solo dos tipos de datos boolean, string
La idea es de que si nos mandan true
agregamos la clase container-fluid
, si nos mandan un string
, agregamos la clase container-{fluid}
, en caso de que sea false
no agregamos nada (ej. de un componente [ref]).
iv. Validaciones avanzadas
a — Arreglos
PropTypes.arrayOf()
En uno de los ejemplos anteriores, habíamos validado que la propiedad fuera un arreglo (PropTypes.array
):
Pero ahora con PropTypes.arrayOf()
, vamos a tener la oportunidad de indicarle qué tipos de datos son los que vamos a aceptar.
Entonces, el componente Profile
, queda de la siguiente manera:
Y la App
:
Podemos observar que en el atributo hobbies
, en ambos estamos mandando un arreglo, solo que uno es tipo string
y el otro es tipo number
, entonces cuando revisamos la aplicación:
Nos sale la advertencia del arreglo de tipo numérico.
Ver ejemplo completo (revisar consola, para ver la advertencia):
Cuando queremos validar más de un tipo de dato, podemos combinarlo con PropTypes.oneOfType
:
En el código de arriba, le estamos indicando que la propiedad multipleArrayProp
va a ser de tipo array
, donde va a aceptar solo 2 tipos de datos number
y string
.
b — Objetos
PropTypes.objectOf()
En uno de los ejemplos anteriores, habíamos validado que la propiedad fuera un objeto (PropTypes.object
):
Pero ahora con PropTypes.objectOf()
, vamos a tener la oportunidad de indicarle qué tipos de datos son los que vamos a aceptar.
Entonces, el componente Profile
, queda de la siguiente manera:
La App
:
Hasta aquí, ninguno de los dos contiene advertencias, ya que ambos están mandando los datos correctos; pero qué pasaría, si quisiéramos agregar el número de casa o departamento donde vive:
En el componente Profile
:
En la App
mandamos el número, dentro del atributo address
:
En pantalla, nos sale la advertencia, debido a que le estamos indicando que addrees: PropTypes.objectOf(PropTypes.string)
todas las propiedades sean de tipo string
Entonces podemos solucionarlo utilizando oneOfType
, de la siguiente manera:
Pero el problema de hacerlo de esta forma, es que podríamos mandarle country
o city
un número y lo marcaría como válido, debido a que le estamos indicando que puede aceptar números o cadenas de texto:
Entonces, usaremos el siguiente método:
PropTypes.shape
: Nos va a servir cuando queremos hacer una validación bastante detallada de un objeto, combinando claves con valores de tipo de dato específico.
Entonces, regresando a nuestro ejemplo, sabemos que:
country:string, city:string, number:number
Nuestra validación quedaría de la siguiente manera:
Y con esto estamos asegurando que cada una de las propiedades tenga el tipo de dato exacto que se requiere.
Ejemplo completo (revisar consola):
Podemos hacer una validación mezclando PropTypes
:
Y la llamada del componente :
PropTypes.exact
: El objeto debe venir con las propiedades exactas ó menos, pero no más.
En nuestro componente solo debemos cambiar el método shape
por exact
:
Ejemplo completo:
v. Validando datos obligatorios
Imaginemos que tenemos el componente Welcome
:
Y queremos decirle al usuario o desarrollador que esa propiedad es obligatoria; con PropTypes
es bastante sencillo, solo debemos encadenar isRequired
, y con esto nos aseguramos que si no viene, nos lance la advertencia.
Nuestra App
:
Toda propiedad que se requiera obligatoria, solo es necesario encadenar isRequired
:
vi. Validaciones personalizadas
a — Básico
PropTypes
, nos da la oportunidad de poner hacer validaciones personales (ej. email, rangos, datos correctos, etc).
:: Sintaxis
:: Ejemplo
Tenemos nuestro componente Welcome
, donde recibe la propiedad name
, la idea va a ser:
- Validar que sí venga la propiedad.
- Validar que tenga al menos 5 caracteres y no mayor a 50
Nuestro, componente sin la validación es el siguiente:
Podemos agregar la validación de dos formas:
- Creando un archivo de validaciones, e importarlo en el componente:
- La otra forma es agregando la función directamente:
Nota: Yo personalmente recomiendo tenerlos en un archivo aparte, con la finalidad de poner reutilizar y el código se vea más limpio.
En nuestra App
:
Ejemplo completo:
:: Ejemplo 2
Imagina que dentro de children
, nos van a mandar una lista, pero nosotros solo aceptamos <li>
, entonces podemos hacer la validación:
Y en nuestro componente ListComponent
:
Nuestra App
Ejemplo completo (ver consola):
b — Para arreglos y objetos
PropTypes
, nos da la oportunidad de hacer validaciones personales de un arreglo arrayOf
o un objeto objectOf
.
:: Sintaxis
:: Ejemplo
Imaginemos que nos mandan un arreglo de edades, donde tenemos que validar que todas sean mayores a 18.
Nuestra validación:
Nuestro componente ListComponent
:
Nuestra App
:
Nos arroja un error en el segundo arreglo, ya que 13 es menor que 18.
Ejemplo completo:
Hasta aquí comprendimos, ¿qué es PropTypes
?, las diferentes formas de validar los tipos de datos de las propiedades de un componente, así como también hacer nuestras propias validaciones.
En la siguiente entrega vamos a ver React — Formas de diseñar componentes de React, desde estilos en línea hasta CSS in JS
La entrega pasada vimos React — Valores por defecto con defaultProps y valores predeterminados con ES6
Bibliografía y links que te puede interesar…