Creación de su propia biblioteca de validación de React: conceptos básicos (Parte 1)

 

 

 

  • Patrones de diseño de interfaces inteligentes, vídeo de 10h + formación UX
  • Anuncie en la revista Smashing

  • Índice
    1. Paso 1: diseñar la API
      1. Una nota sobre los ganchos
    2. Almacenamiento del estado del formulario
    3. ¿Qué es un reductor?
    4. Validando nuestro formulario
      1. Cómo elegir funciones de validador
      2. Validar un solo campo
    5. Nota: en las API del validador
    6. Nota: On for…in bucles
      1. Validar todos los campos
      2. Siguiente: Dígale a nuestro reductor
    7. Manejo del envío de formularios
    8. Resumen

    ¿Alguna vez te has preguntado cómo funcionan las bibliotecas de validación? Este artículo le dirá cómo crear su propia biblioteca de validación para React paso a paso. La siguiente parte agregará algunas funciones más avanzadas y la parte final se centrará en mejorar la experiencia del desarrollador.

     

    Siempre pensé que las bibliotecas de validación de formularios eran geniales. Lo sé, es un interés de nicho, ¡pero los usamos mucho! Al menos en mi trabajo, la mayor parte de lo que hago es construir formas más o menos complejas con reglas de validación que dependen de elecciones y caminos anteriores. Es fundamental comprender cómo funcionaría una biblioteca de validación de formularios.

    El año pasado, escribí una de esas bibliotecas de validación de formularios. Lo llamé " Calidación " y puedes leer la publicación introductoria del blog aquí . Es una buena biblioteca que ofrece mucha flexibilidad y utiliza un enfoque ligeramente diferente al resto del mercado. Sin embargo, también existen muchas otras bibliotecas excelentes; la mía simplemente funcionó bien para nuestros requisitos.

     

    Hoy te mostraré cómo escribir tu propia biblioteca de validación para React. Revisaremos el proceso paso a paso y encontrará ejemplos de CodeSandbox a medida que avancemos. Al final de este artículo, sabrá cómo escribir su propia biblioteca de validación o, al menos, tendrá una comprensión más profunda de cómo otras bibliotecas implementan "la magia de la validación".

    • Parte 1: Conceptos básicos
    • Parte 2: Las características
    • Parte 3: La experiencia

    Paso 1: diseñar la API

    El primer paso para crear cualquier biblioteca es diseñar cómo se utilizará. Sienta las bases para gran parte del trabajo futuro y, en mi opinión, es la decisión más importante que vas a tomar en tu biblioteca.

    Es importante crear una API que sea "fácil de usar" y, al mismo tiempo, lo suficientemente flexible como para permitir futuras mejoras y casos de uso avanzados. Intentaremos alcanzar ambos objetivos.

    Vamos a crear un gancho personalizado que aceptará un único objeto de configuración. Esto permitirá que se aprueben opciones futuras sin introducir cambios importantes.

    Una nota sobre los ganchos

    Hooks es una forma bastante nueva de escribir React. Si ha escrito React en el pasado, es posible que no reconozca algunos de estos conceptos. En ese caso, eche un vistazo a la documentación oficial . Está increíblemente bien escrito y le explica los conceptos básicos que necesita saber.

    Vamos a llamar a nuestro gancho personalizado useValidationpor ahora. Su uso podría verse así:

    const config = { fields: { username: { isRequired: { message: 'Please fill out a username' }, }, password: { isRequired: { message: 'Please fill out a password' }, isMinLength: { value: 6, message: 'Please make it more secure' } } }, onSubmit: e = { /* handle submit */ }};const { getFieldProps, getFormProps, errors } = useValidation(config);

    El configobjeto acepta una fieldspropiedad, que configura las reglas de validación para cada campo. Además, acepta una devolución de llamada cuando se envía el formulario.

    El fieldsobjeto contiene una clave para cada campo que queremos validar. Cada campo tiene su propia configuración, donde cada clave es un nombre de validador y cada valor es una propiedad de configuración para ese validador. Otra forma de escribir lo mismo sería:

    { fields: { fieldName: { oneValidator: { validatorRule: 'validator value' }, anotherValidator: { errorMessage: 'something is not as it should' } } }}

    Nuestro useValidationgancho devolverá un objeto con algunas propiedades getFieldProps: getFormPropsy errors. Las dos primeras funciones son lo que Kent C. Dodds llama "captadores de propiedades" ( consulte aquí un excelente artículo sobre ellas ) y se utilizan para obtener las propiedades relevantes para un campo o etiqueta de formulario determinado. El errorsaccesorio es un objeto con mensajes de error, ingresados ​​por campo.

     

    Este uso se vería así:

    const config = { ... }; // like aboveconst LoginForm = props = { const { getFieldProps, getFormProps, errors } = useValidation(config); return ( form {...getFormProps()} label Usernamebr/ input {...getFieldProps('username')} / {errors.username div className="error"{errors.username}/div} /label label Passwordbr/ input {...getFieldProps('password')} / {errors.password div className="error"{errors.password}/div} /label button type="submit"Submit my form/button /form );};

    ¡Muy bien! Así que hemos logrado la API.

    • Ver demostración de CodeSandbox

    useValidationTenga en cuenta que también hemos creado una implementación simulada del gancho. Por ahora, solo devuelve un objeto con los objetos y funciones que requerimos que estén allí, para no interrumpir nuestra implementación de muestra.

    Almacenamiento del estado del formulario

    Lo primero que debemos hacer es almacenar todo el estado del formulario en nuestro gancho personalizado. Necesitamos recordar los valores de cada campo, cualquier mensaje de error y si el formulario se ha enviado o no. Usaremos el useReducergancho para esto ya que permite la mayor flexibilidad (y menos repetición). Si alguna vez has usado Redux , verás algunos conceptos familiares y, si no, ¡te los explicaremos a medida que avancemos! Comenzaremos escribiendo un reductor, que se pasa al useReducergancho:

    const initialState = { values: {}, errors: {}, submitted: false,};function validationReducer(state, action) { switch(action.type) { case 'change': const values = { ...state.values, ...action.payload }; return { ...state, values, }; case 'submit': return { ...state, submitted: true }; default: throw new Error('Unknown action type'); }}

    ¿Qué es un reductor?

    Un reductor es una función que acepta un objeto de valores y una "acción" y devuelve una versión aumentada del objeto de valores.

    Las acciones son objetos simples de JavaScript con una typepropiedad. Estamos usando una switchdeclaración para manejar cada tipo de acción posible.

    El "objeto de valores" a menudo se denomina estado y, en nuestro caso, es el estado de nuestra lógica de validación.

    Nuestro estado consta de tres datos: values(los valores actuales de los campos de nuestro formulario), errors(el conjunto actual de mensajes de error) y una bandera isSubmittedque indica si nuestro formulario se ha enviado o no al menos una vez.

    Para almacenar el estado de nuestro formulario, necesitamos implementar algunas partes de nuestro useValidationgancho. Cuando llamamos a nuestro getFieldPropsmétodo, necesitamos devolver un objeto con el valor de ese campo, un controlador de cambios para cuando cambia y un nombre de propiedad para rastrear qué campo es cuál.

     

    function validationReducer(state, action) { // Like above}const initialState = { /* like above */ };const useValidation = config = { const [state, dispatch] = useReducer(validationReducer, initialState); return { errors: state.errors, getFormProps: e = {}, getFieldProps: fieldName = ({ onChange: e = { if (!config.fields[fieldName]) { return; } dispatch({ type: 'change', payload: { [fieldName]: e.target.value } }); }, name: fieldName, value: state.values[fieldName], }), };};

    El getFieldPropsmétodo ahora devuelve los accesorios necesarios para cada campo. Cuando se activa un evento de cambio, nos aseguramos de que ese campo esté en nuestra configuración de validación y luego le informamos a nuestro reductor que changese llevó a cabo una acción. El reductor manejará los cambios en el estado de validación. Mejores Opiniones y reviews

    • Ver demostración de CodeSandbox

    Validando nuestro formulario

    Nuestra biblioteca de validación de formularios se ve bien, ¡pero no hace mucho en términos de validar los valores de nuestros formularios! Arreglemos eso.

    Validaremos todos los campos en cada evento de cambio. Puede que esto no parezca muy eficiente, pero en las aplicaciones del mundo real con las que me he encontrado, no es realmente un problema.

    Tenga en cuenta que no estamos diciendo que deba mostrar todos los errores en cada cambio. Volveremos a ver cómo mostrar errores solo cuando envíe o navegue fuera de un campo más adelante en este artículo.

    Cómo elegir funciones de validador

    Cuando se trata de validadores, existen toneladas de bibliotecas que implementan todos los métodos de validación que pueda necesitar. También puedes escribir el tuyo propio si quieres. ¡Es un ejercicio divertido!

    Para este proyecto, usaremos un conjunto de validadores que escribí hace algún tiempo: calidators. Estos validadores tienen la siguiente API:

    function isRequired(config) { return function(value) { if (value === '') { return config.message; } else { return null; } };}// or the same, but terserconst isRequired = config = value = value === '' ? config.message : null;

    En otras palabras, cada validador acepta un objeto de configuración y devuelve un validador completamente configurado. Cuando se llama a esa función con un valor, devuelve la messagepropiedad si el valor no es válido o nullsi es válido. Puede ver cómo se implementan algunos de estos validadores consultando el código fuente .

    Para acceder a estos validadores, instale el calidatorspaquete con npm install calidators.

    Validar un solo campo

    ¿Recuerdas la configuración que le pasamos a nuestro useValidationobjeto? Se parece a esto:

    { fields: { username: { isRequired: { message: 'Please fill out a username' }, }, password: { isRequired: { message: 'Please fill out a password' }, isMinLength: { value: 6, message: 'Please make it more secure' } } }, // more stuff}

    Para simplificar nuestra implementación, supongamos que solo tenemos un campo para validar. Revisaremos cada clave del objeto de configuración del campo y ejecutaremos los validadores uno por uno hasta que encontremos un error o terminemos de validar.

     

    import * as validators from 'calidators';function validateField(fieldValue = '', fieldConfig) { for (let validatorName in fieldConfig) { const validatorConfig = fieldConfig[validatorName]; const validator = validators[validatorName]; const configuredValidator = validator(validatorConfig); const errorMessage = configuredValidator(fieldValue); if (errorMessage) { return errorMessage; } } return null;}

    Aquí, hemos escrito una función validateFieldque acepta el valor a validar y las configuraciones del validador para ese campo. Recorremos todos los validadores, les pasamos la configuración de ese validador y lo ejecutamos. Si recibimos un mensaje de error, omitimos el resto de validadores y regresamos. Si no, probamos con el siguiente validador.

    Nota: en las API del validador

    Si elige diferentes validadores con diferentes API (como el muy popular validator.js), esta parte de su código puede verse un poco diferente. Sin embargo, en aras de la brevedad, dejamos que esa parte sea un ejercicio para el lector.

    Nota: On for…in bucles

    ¿ Nunca has usado for...inbucles antes? Está bien, ¡esta también fue mi primera vez! Básicamente, itera sobre las claves de un objeto. Puedes leer más sobre ellos en MDN .

    Validar todos los campos

    Ahora que hemos validado un campo, deberíamos poder validar todos los campos sin demasiados problemas.

    function validateField(fieldValue = '', fieldConfig) { // as before}function validateFields(fieldValues, fieldConfigs) { const errors = {}; for (let fieldName in fieldConfigs) { const fieldConfig = fieldConfigs[fieldName]; const fieldValue = fieldValues[fieldName]; errors[fieldName] = validateField(fieldValue, fieldConfig); } return errors;}

    Hemos escrito una función validateFieldsque acepta todos los valores de campo y la configuración completa del campo. Recorremos cada nombre de campo en la configuración y validamos ese campo con su objeto y valor de configuración.

    Siguiente: Dígale a nuestro reductor

    Muy bien, ahora tenemos esta función que valida todas nuestras cosas. ¡Incorporémoslo al resto de nuestro código!

    Primero, agregaremos un validatecontrolador de acciones a nuestro archivo validationReducer.

    function validationReducer(state, action) { switch (action.type) { case 'change': // as before case 'submit': // as before case 'validate': return { ...state, errors: action.payload }; default: throw new Error('Unknown action type'); }}

    Cada vez que activamos la validateacción, reemplazamos los errores en nuestro estado con lo que se pasó junto con la acción.

    A continuación, activaremos nuestra lógica de validación desde un useEffectgancho:

    const useValidation = config = { const [state, dispatch] = useReducer(validationReducer, initialState); useEffect(() = { const errors = validateFields(state.fields, config.fields); dispatch({ type: 'validate', payload: errors }); }, [state.fields, config.fields]); return { // as before };};

    Este useEffectgancho se ejecuta cada vez que nuestro state.fieldso config.fieldscambia, además del primer montaje.

     

    Cuidado con los errores

    Hay un error súper sutil en el código anterior. Hemos especificado que nuestro useEffectgancho solo debe volver a ejecutarse cada vez que state.fieldso config.fieldscambie. Resulta que “cambiar” no significa necesariamente un cambio de valor. useEffectutiliza Object.ispara garantizar la igualdad entre objetos, que a su vez utiliza la igualdad de referencia. Es decir, si pasa un objeto nuevo con el mismo contenido, no será el mismo (ya que el objeto en sí es nuevo).

    Se state.fieldsdevuelven desde useReducer, lo que nos garantiza esta igualdad de referencia, pero nuestro configse especifica en línea en nuestro componente de función. Eso significa que el objeto se recrea en cada renderizado, lo que a su vez desencadenará lo useEffectanterior.

    Para solucionar esto, necesitamos utilizar para la use-deep-compare-effectbiblioteca de Kent C. Dodds. Lo instalas con npm install use-deep-compare-effecty reemplazas tu useEffectllamada con esto. Esto asegura que hagamos una verificación de igualdad profunda en lugar de una verificación de igualdad de referencia.

    Su código ahora se verá así:

    import useDeepCompareEffect from 'use-deep-compare-effect';const useValidation = config = { const [state, dispatch] = useReducer(validationReducer, initialState); useDeepCompareEffect(() = { const errors = validateFields(state.fields, config.fields); dispatch({ type: 'validate', payload: errors }); }, [state.fields, config.fields]); return { // as before };};

    Una nota sobre el efecto de uso

    Resulta que useEffectes una función bastante interesante. Dan Abramov escribió un artículo realmente largo y agradable sobre las complejidades deuseEffect si está interesado en aprender todo lo que hay sobre este gancho.

    ¡Ahora las cosas empiezan a parecerse a una biblioteca de validación!

    • Ver demostración de CodeSandbox

    Manejo del envío de formularios

    La última parte de nuestra biblioteca de validación de formularios básica es manejar lo que sucede cuando enviamos el formulario. Ahora mismo recarga la página y no pasa nada. Eso no es óptimo. Queremos evitar el comportamiento predeterminado del navegador cuando se trata de formularios y, en su lugar, manejarlo nosotros mismos. Colocamos esta lógica dentro de la getFormPropsfunción de obtención de accesorios:

    const useValidation = config = { const [state, dispatch] = useReducer(validationReducer, initialState); // as before return { getFormProps: () = ({ onSubmit: e = { e.preventDefault(); dispatch({ type: 'submit' }); if (config.onSubmit) { config.onSubmit(state); } }, }), // as before };};

    Cambiamos nuestra getFormPropsfunción para devolver una onSubmitfunción, que se activa cada vez que submitse activa el evento DOM. Prevenimos el comportamiento predeterminado del navegador, enviamos una acción para informarle a nuestro reductor que enviamos y llamamos a la onSubmitdevolución de llamada proporcionada con el estado completo, si se proporciona.

    Resumen

    ¡Estaban allí! Hemos creado una biblioteca de validación simple, utilizable y bastante interesante. Sin embargo, todavía queda mucho trabajo por hacer antes de que podamos dominar Internet.

    • Parte 1: Conceptos básicos
    • Parte 2: Las características
    • Parte 3: La experiencia

    (dm, il)Explora más en

    • Reaccionar
    • javascript
    • Pruebas
    • Formularios





    Tal vez te puede interesar:

    1. Creación de su propia biblioteca de validación de React: la experiencia del desarrollador (Parte 3)
    2. Introducción a Quasar Framework: creación de aplicaciones multiplataforma
    3. Creación de un componente web retro que se puede arrastrar con iluminación
    4. Creación y acoplamiento de una aplicación Node.js con arquitectura sin estado con la ayuda de Kinsta

    Creación de su propia biblioteca de validación de React: conceptos básicos (Parte 1)

    Creación de su propia biblioteca de validación de React: conceptos básicos (Parte 1)

    Patrones de diseño de interfaces inteligentes, vídeo de 10h + formación UX Anuncie en la revista Smashing Índice

    programar

    es

    https://aprendeprogramando.es/static/images/programar-creacion-de-su-propia-biblioteca-de-validacion-de-react-conceptos-basicos-parte-1-984-0.jpg

    2024-05-20

     

    Creación de su propia biblioteca de validación de React: conceptos básicos (Parte 1)
    Creación de su propia biblioteca de validación de React: conceptos básicos (Parte 1)

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20