Nuevo paquete de validación para React on Mobx @ quantumart / mobx-form-validation-kit

Buenas tardes
Hoy quiero hablar sobre un nuevo paquete para validaciones asíncronas en proyectos basados ​​en React , Mobx y escritos en Typecript .
El desarrollo moderno de Frontend implica una gran cantidad de lógica al completar páginas con documentos, cuestionarios y documentos para un préstamo, órdenes de pago, páginas de registro en el sitio. La carga lógica principal recae en las verificaciones de validación. Los desarrolladores angulares reflexionaron sobre este punto y ofrecen a los desarrolladores el uso del mecanismo incorporado de FormControl para estos fines, que, aunque tiene una serie de inconvenientes, es aún mejor que la ausencia total de tal solución en React . La situación se complica por el hecho de que la tendencia actual del desarrollo de React implica el uso de mobx para organizar la lógica empresarial.
Ante estos problemas, los resolvimos todos escribiendo un paquete: @ quantumart / mobx-form-validation-kit

Ventajas del paquete:
  • Completamente en TypeScript
  • Compatible con Mobx (versión 4, que admite, el favorito de todos, IE10)
  • Diseñado para trabajar en React (se puede usar en proyectos sin reaccionar)
  • Diseñado para validación asincrónica
  • Fácil de integrar en un proyecto existente.

Instrucciones para trabajar con el paquete debajo del corte.


Al principio describiremos la funcionalidad del paquete @ quantumart / mobx-form-validation-kit , al final del artículo escribiremos una página completamente funcional con un ejemplo del formulario de registro en el sitio.

Control de forma


@ quantumart / mobx-form-validation-kit le permite crear una capa entre los datos de origen y el formulario para mostrar. Lo que, a su vez, le permite validarlos y, si es necesario, cambiar los datos antes de que lleguen al objeto original.

La biblioteca @ quantumart / mobx-form-validation-kit contiene tres clases principales (componentes de validación) para administrar el formulario:
  • FormGroup : le permite combinar componentes de validación juntos. La clase se escribe y le permite rehacer la interfaz con la lista de campos como un parámetro genérico. Cualquiera está registrado de manera predeterminada, se recomienda no usarlo sin escribir, pero existe la posibilidad.
  • FormControl : se utiliza para validar un campo específico, la clase más utilizada. La clase se escribe y toma como parámetro genérico el tipo de variable que debe almacenar. Por defecto, la cadena está registrada, porque el valor predeterminado es string, como la opción más privada para formularios.
  • FormArray : le permite crear y administrar una variedad de componentes de validación.

Además, hay clases abstractas básicas.
  • AbstractControl : la clase base para todas las clases de validación enumeradas, no escrita.
  • FormAbstractControl : clase base para FormGroup y FormArray , sin escribir.
  • FormAbstractGroup : no es una clase base escrita para FormControl, contiene un enlace al elemento html que se está representando.

La mejor práctica para crear un formulario de validación sería la siguiente idea.
Se crea un objeto de tipo uno FormGroup en el formulario y los campos ya están listados en él
this.form = new FormGroup<IUserInfo>({ name: new FormControl( this.userInfo.name, [], v => (this.userInfo.name = v) ), surname: new FormControl( this.userInfo.surname, [], v => (this.userInfo.surname = v) ) // … }); 

FormGroup admite la anidación, es decir
 this.form = new FormGroup<IUserInfo>({ name: new FormControl( this.userInfo.name, [], v => (this.userInfo.name = v) ), surname: new FormControl( this.userInfo.surname, [], v => (this.userInfo.surname = v) ) passport: new FormGroup<IPassport >({ number: new FormControl( this.userInfo.passport.number, [], v => (this.userInfo.passport.number = v) ), // … }) // … }); 

Puede agregar FormArray , que a su vez puede pasar el tipo FormControl o todo el FormGroup creando objetos de cualquier complejidad y estructura.
  • FormArray <FormControl>
    FormArray <FormGroup>

    FormControl mismo toma el siguiente conjunto de parámetros en el constructor
    • valor : TEntity es el valor inicial escrito.
    • validadores : ValidatorFunctionFormControlHandler [] - un conjunto de validadores.
    • callbackValidValue : UpdateValidValueHandler | nulo: función de devolución de llamada a la que se pasa el último valor válido. Se llama cada vez que cambia un valor en FormControl y este valor pasa las validaciones descritas.
    • activar : (() => booleano) | nulo: la función habilitará / deshabilitará las validaciones por condición (siempre habilitada por defecto). Por ejemplo, no es necesario verificar la validez de la fecha de finalización del servicio si la casilla de verificación "Ilimitado" no está marcada. Como resultado, simplemente ingresando una función aquí que marca el estado del campo observable responsable de la casilla de verificación "Ilimitado", puede desactivar automáticamente todas las validaciones asociadas con el campo para verificar la fecha, en lugar de registrar esta lógica en cada una de las validaciones de campo de fecha.
    • AdditionalData: TAdditionalData | nulo: un bloque con información adicional le permite agregar información adicional a un FormControl específico y usarlo más tarde, por ejemplo, para visualización. Esto es conveniente si hay creadores de FormControl en los que necesita analizar cierta información y no pasar esta información a través de un paquete de datos complejo a los controles para su visualización. Aunque no puedo dar un escenario de aplicación exacto e innegable, es mejor tener esa oportunidad que sufrir sin ella.

    Angular FormControl también tiene una limitación: no es necesario reutilizar objetos en diferentes formas. Es decir Puede crear un generador de FormGroup y crear su propio objeto en cada página. Pero usar un objeto por grupo de páginas es una mala práctica.
    Además, FormControl se inicializa con un solo valor, y si se cambia este valor, el nuevo valor no entrará en FormControl . Esto se hace a propósito, porque, como lo ha demostrado la práctica, por alguna razón, todos intentan obstinadamente editar inicialmente el objeto original sin pasar por las validaciones, y no el valor en FormControl . Simplemente asigne un nuevo valor al campo de valor de FormControl para modificar el objeto original.
    FormGroup acepta el siguiente conjunto de parámetros en el constructor:
    • controles : TControls: un objeto heredado de AbstractControls . De hecho, simplemente cree una interfaz heredada de AbstractControls en la que enumere campos del tipo FormGroup , FormControl , FormArray . Por supuesto, puede establecer el tipo en cualquiera , pero se perderán todas las ventajas de TypeScript .
    • validadores : ValidatorFunctionFormGroupHandler [] - un conjunto de validadores para valores de grupo. Por ejemplo, puede crear un FormGroup que contenga dos valores: la fecha mínima y máxima, para el control de selección de período. Es en estos validadores que necesitará pasar la función / funciones de verificar el rango de fechas. Por ejemplo, que la fecha de inicio no es mayor que la fecha de finalización
    • activar : (() => booleano) | nulo: la función habilitará / deshabilitará las validaciones por condición (siempre habilitada por defecto). Debe entenderse que la aplicación de la función de validación a un grupo deshabilita la validación a nivel de todo el grupo. Por ejemplo, tenemos un cuadro de selección para un documento de identidad. Puede crear varios FormGroups con un conjunto diferente de campos para documentos: pasaporte, licencia de conducir, pasaporte de marinero, etc. En esta función, verifique los valores desplegables y, si el valor seleccionado no corresponde a este grupo, todas las verificaciones de validación están deshabilitadas. Más precisamente, el grupo se considerará válido, independientemente de los valores que contenga.

    Hablemos de los campos de FormControl , incluida la presencia de FormGroup y FormArray .
    • ControlTypes - tipo de control (Control | Grupo | Matriz)
    • procesamiento : booleano: en el proceso de análisis. Porque Se admiten validaciones asincrónicas, por ejemplo, aquellas que requieren una solicitud del servidor. El estado actual de la exploración se puede encontrar en este campo.
      Además, FormGroup y FormArray admiten el método de espera , que le permite esperar a que se complete la verificación. Por ejemplo, cuando hace clic en el botón "enviar datos", debe registrar el siguiente diseño.
       await this.form.wait(); if (this.form.invalid) { … 

    • disabled : boolean: la comprobación de errores está desactivada (el control siempre es válido)
    • activo : booleano: la comprobación de errores está habilitada. Depende del resultado de la función de activación. Este valor es muy conveniente para ocultar un grupo de campos en un formulario y no escribir funciones adicionales y duplicadas de la lógica empresarial.
    • inválido : booleano; - para FormControl : significa que el campo contiene errores de validación. Para FormGroup y FormArray, significa que el control de grupo en sí contiene errores o que uno de los campos anidados (en cualquiera de los niveles de anidación) contiene errores de validación. Es decir para verificar la validez de todo el formulario, es suficiente realizar una verificación no válida o válida del FormGroup superior.
    • válido : booleano, para FormControl , significa que el campo no contiene errores de validación. Para FormGroup y FormArray, significa que el control de grupo en sí no contiene errores y ninguno de los campos anidados (en cualquier nivel de anidación) contiene errores de validación.
    • prístino : booleano: el valor en el campo, después de la inicialización con el valor predeterminado, no cambió.
    • dirty : boolean: el valor en el campo, después de la inicialización con el valor predeterminado, cambió.
    • intacto : boolean - para FormControl - significa que el campo (por ejemplo, entrada) no estaba enfocado. For FormGroup y FormArray significa que ninguno de los FormControls anidados estaban enfocados. Un valor de falso en este campo significa que el foco no solo se estableció, sino que también se eliminó del campo.
    • touch : boolean - Para FormControl - significa que el campo (por ejemplo, entrada) estaba enfocado. Para FormGroup y FormArray , significa que uno de los FormControls anidados estaba enfocado. Un valor de verdadero en este campo significa que el foco no solo se estableció, sino que también se eliminó del campo.
    • focus : boolean - para FormControl - significa que el campo (por ejemplo, entrada) ahora está enfocado. Para FormGroup y FormArray , significa que uno de los FormControls anidados ahora está enfocado.
    • errores : ValidationEvent []: el campo contiene errores de validación. A diferencia de los campos enumerados, esta matriz contiene exactamente los errores de FormControl , FormGroup o FormArray , es decir. errores de este control, y no todos anidados. Afecta campo válido / inválido
    • advertencias : ValidationEvent []: el campo contiene mensajes de advertencia. A diferencia de los campos enumerados, esta matriz contiene exactamente los errores de FormControl, FormGroup o FormArray, es decir. mensajes de este control, pero no todos adjuntos. No afecta el campo válido / inválido
    • informationMessages : ValidationEvent []: el campo contiene mensajes informativos. A diferencia de los campos enumerados, esta matriz contiene exactamente los errores de FormControl, FormGroup o FormArray, es decir. mensajes de este control, pero no todos adjuntos. No afecta el campo válido / inválido
    • successes : ValidationEvent: el campo contiene mensajes de validez adicionales. A diferencia de los campos enumerados, esta matriz contiene exactamente los errores de FormControl, FormGroup o FormArray, es decir. mensajes de este control, pero no todos adjuntos. No afecta el campo válido / inválido
    • maxEventLevel () : el nivel máximo de mensajes de validación actualmente en el campo.
    • El método devolverá uno de los valores de enumeración, en la siguiente prioridad.
      1. ValidationEventTypes.Error;
      2. ValidationEventTypes.Warning;
      3. ValidationEventTypes.Info;
      4. ValidationEventTypes.Success;

    • serverErrors : string []: después de enviar un mensaje al servidor, también es una buena forma de verificar la validez del formulario en el servidor. Como resultado, el servidor puede devolver errores de la verificación de formulario final, y la matriz serverErrors está destinada a estos errores. Una característica clave de serverErrors es la limpieza automática de los mensajes de validación cuando se pierde el foco del campo al que se asignaron los errores del servidor, y los errores del servidor también se borran si el campo se ha cambiado.
    • onChange: Delegate - además del mecanismo estándar mobx - reacción, puede usar delegar y agregarle una función de devolución de llamada, que se llama cuando cambian los datos.
    • setDirty (dirty: boolean): void: el método le permitirá cambiar el valor de los campos prístinos / sucios
    • setTouched (tocado: booleano): vacío; - el método le permitirá cambiar el valor de los campos no tocados / tocados
    • disponer (): vacío; - requerido para llamar al control responsable de la página en componentWillUnmount.


    Estos eran campos comunes para todos los controles, pero cada control también tiene campos únicos para su tipo.
    Control de forma
    • valor : contiene el valor actual del campo. También puede asignar un nuevo valor a este campo.


    FormGroup y FormArray contienen
    • esperar : el método le permite esperar el final de las comprobaciones de todas (validaciones), incluidas las anidadas
    • allControls () : este método le permite obtener un conjunto completo de todos los FormControl, incluidos los anidados en diferentes niveles. Es decir de hecho, expande un objeto FormGroup multinivel, que también puede contener FormGroup, en una lista grande que consta solo de FormControl. Esta funcionalidad es necesaria si queremos encontrar el primer elemento no válido y enfocarnos en él.
      el código, en este caso, se vería así:
       await this.form.wait(); if (this.form.invalid) { this.form.setTouched(true); const firstError = this.form.allControls().find(c => c.invalid && !!c.element); if (!!firstError) { firstError.element.focus(); } } ... 



    Validaciones


    Por supuesto, además de los controles que le permiten trabajar con datos, también necesitamos validaciones. El paquete @ quantumart / mobx-form-validation-kit contiene naturalmente una serie de validaciones predefinidas, y también admite la creación de validaciones personalizadas personalizadas.
    Un ejemplo de configuración de validaciones para FormControl para un campo de edad.
     new FormControl<number>( this.userInfo.age, [required(), minValue(18, "    18 .", ValidationEventTypes.Warning)], v => (this.userInfo.age = v) ) 

    Cada validación con los últimos parámetros lleva:
    • Mensaje: un mensaje de validación.
    • eventType: nivel de mensaje. Se admiten 4 niveles de mensaje.
      1. Error - errores
      2. Advertencia - advertencias
      3. Información - Mensajes informativos
      4. Éxito: mensajes sobre validez. Por ejemplo, puede verificar que la contraseña sea realmente compleja.


    El paquete contiene el siguiente conjunto de validaciones:
    • obligatorio (... - campo obligatorio
    • notEmptyOrSpaces (... - el campo no está vacío y no contiene solo espacios. De hecho, es obligatorio, teniendo en cuenta la prohibición de espacios.
    • patrón (regExp: RegExp, ... - el primer parámetro es la expresión regular que debe coincidir con el campo. Se genera un error si no hay coincidencia de patrones.
    • invertPattern (regExp: RegExp, ... - el primer parámetro es la expresión regular que el campo no debe coincidir. Se genera un error si hay una coincidencia de patrón.
    • minLength (minlength: number, .... - el primer parámetro es la longitud mínima del texto inclusive. Se genera un error si la longitud es menor que la transmitida.
    • maxLength (maxlength: number, .... - el primer parámetro es la longitud máxima del texto inclusive. Se emite un error si la longitud es más larga que la transmitida.
    • absoluteLength (longitud: número, .... - el primer parámetro es la longitud exacta del texto. Se emite un error si la longitud no coincide con la especificada.
    • minValue (min: TEntity | (() => TEntity), ... - esta validación está destinada solo para números y fechas. Se establece un error si el valor es menor que el especificado. La peculiaridad de la validación es la capacidad de aceptar no solo un valor específico, sino también función, lo que significa que si lee el valor en esta función desde el campo @observable del objeto, la validación en sí misma se reiniciará no solo cuando se cambie el campo en el que se colgó la validación, sino también cuando se cambie el "campo vinculado". primer campo de etiqueta excepto que se lee como el valor @observable.
    • maxValue (max: TEntity | (() => TEntity), ... - esta validación está destinada solo para números y fechas. Se establece un error si el valor es mayor que el especificado. La función de validación es la capacidad de aceptar no solo un valor específico, sino también función, lo que significa que si lee el valor en esta función desde el campo @observable del objeto, la validación en sí misma se reiniciará no solo cuando se cambie el campo en el que se colgó la validación, sino también cuando se cambie el "campo vinculado". primero, salvo campo de etiqueta que se lee como el valor @observable
    • notContainSpaces (... - a diferencia de notEmptyOrSpaces, se emitirá un error si el valor incluso contiene al menos un espacio.
    • compare (expression: (value: TEntity) => boolean (... - escribir su propia función de validación genera una gran cantidad de código de copiar y pegar, este contenedor fue desarrollado para deshacerse de este problema. Esta función de validación acepta una función como primer parámetro, que a su vez pasa el valor actual campos, lo que le permite realizar una verificación compleja, por ejemplo, calcular el hash para el TIN o el número de pasaporte, y luego devolver verdadero / falso. Se mostrará un error si la verificación devuelve falso.
    • isEqual (valor: cadena ... - una simple verificación de coincidencia de cadena.

    A continuación se describen las funciones de contenedor que controlan el flujo de activadores de validación.
    Cabe señalar que el conjunto de validaciones pasadas a FormControl , FormGroup , FormArray se inicia en una sola matriz y, de hecho, no tiene secuencia de ejecución. Como resultado del trabajo, tendremos en los campos errores , advertencias , mensajes de información , matrices de éxitos que consisten en errores, advertencias, combinadas en una sola matriz, etc.
    A menudo, el cliente quiere ver solo un error, y no todos a la vez. Además, el TOR puede diseñarse de modo que una verificación se realice solo después de que la anterior haya pasado.
    Para resolver este problema, se usa wrapperSequentialCheck . Su llamada y su aplicación no son diferentes del validador de funciones habitual, pero en la entrada recibe una matriz de validadores que se lanzarán secuencialmente, es decir. La siguiente validación solo comienza después de que la anterior pasó sin errores.
    La segunda función de envoltura es la función de control de flujo de las validaciones. wrapperActivateValidation ya que el primer parámetro toma una función en la que se deben escribir las condiciones para la activación de la validación. A diferencia de la función de activación que se pasa a FormControl, esta verificación está diseñada para una lógica más compleja. Supongamos que tenemos un generador común para toda la forma de pago FormGroup , y además, solo hay un método en el servidor que acepta un conjunto común de campos. Pero el problema es que, aunque el formulario es uno, dependiendo del "tipo de pago" mostramos un conjunto diferente de campos al usuario. Entonces wrapperActivateValidation le permite escribir lógica en la que se llevarán a cabo varias comprobaciones según el tipo de pago.
    El uso de envoltorios se verá como funciones comunes.
     new FormControl( this.userInfo.megapole, [wrapperActivateValidation(() => this.info.A === 10, [ required(), pattern(/\^d{10}$/) ]), wrapperActivateValidation(() => this.info.A === 20, [ wrapperSequentialCheck([ notContainSpaces(), pattern(/\^d{20}$/) ]) ])], v => (this.userInfo.megapole = v) ) 

    Este ejemplo muestra que las comprobaciones requeridas (), de patrón (/ \ ^ d {10} $ /) solo se realizarán con this.info.A === 10 , y si this.info.A === 20 , luego notContainSpaces (), las validaciones de patrón (/ \ ^ d {20} $ /) funcionarán, además, estas validaciones funcionarán secuencialmente, a diferencia del primer caso.

    Naturalmente, llegará el momento en que el conjunto estándar de validaciones ya no sea suficiente.
    Luego tienes que escribir tus propias funciones asincrónicas. Afortunadamente, esto se hace sin ninguna dificultad especial.
    FormControl se agudizó originalmente mediante funciones de validación asincrónicas, que podrían querer ir al servidor para obtener datos, y esta respuesta debe esperar. Y como resultado, todas las validaciones son asíncronas.
     async function checkValueOnServer(control: FormControl): Promise<ValidationEvent[]> { if (control.value == null) { return []; } const result = await sendToServer(control.value); if (result.errorMessage) { return [ { message: result.errorMessage, type: ValidationEventTypes.Error, }, ]; } return []; } 

    Aquí debe prestar atención a dos objetos.
    Primero, siempre nos importa la matriz. Es decir de hecho, puede devolver varios mensajes de error a la vez, si lo desea.
    El segundo punto es el objeto devuelto; tiene el siguiente conjunto de campos.
    • key ?: string - un campo opcional, le permite especificar una "clave" para una validación específica. Para todas las claves base, la clave es única y coincide con su nombre. Es posible que desee utilizar la clave para hacer que la lista reaccione, pero como ha demostrado la práctica, esta es una mala idea. En el futuro, en el ejemplo, mostraré que es mejor usar el mensaje y no tocar la tecla en absoluto. En cualquier caso, es, como en Angunar, pero su necesidad se ha reducido, de hecho, a 0.
    • mensaje : cadena - un mensaje de validación. Campo obligatorio
    • tipo : ValidationEventTypes - tipo de mensaje.
      1. Error - errores
      2. Advertencia - advertencias
      3. Información - Mensajes informativos
      4. Éxito: mensajes sobre validez. Por ejemplo, puede verificar que la contraseña sea realmente compleja.

    • AdditionalData ?: any: información adicional que se puede transmitir junto con la validación, si es necesario. Puede ser un marcado html adicional o un estilo específico. En general, puede poner todo en cualquiera.


    Extensiones


    Cualquier magia se basa en cosas triviales. Y en este caso, para que funcione la configuración de enfoque, obtener cambios de los campos requiere vincular el FormControl en un campo de entrada específico.
    Porque FormControl no limita al desarrollador en el tipo de datos validados, debido a su versatilidad, fue necesario sacrificar un poco de aplicabilidad en los elementos de reacción.
    Al mismo tiempo, para la entrada y el área de texto fue posible crear funciones simples de vinculación de datos en un elemento; para otros componentes, el procesador aún tendrá que hacer un esfuerzo mínimo para sustituir los datos.

    Para la entrada, el enlace del elemento a FormControl (nombre) se verá así.
    <input type = "text" {... InputFormControl.bindActions (controls.name)} />
    Para textarea, el enlace será así
    <textarea {... TextAreaFormControl.bindActions (controls.name)} />

    InputFormControl.bindActions y TextAreaFormControl.bindActions aceptan dos parámetros:
    • formControl : FormControl - en realidad FormControl que se usará para el enlace. Requerido
    • eventos ? - Un parámetro opcional que contiene una lista de funciones a las que se puede llamar si necesita personalizarlas. , bindActions - Element, , element FormControl -, . . event. .
      • ref
      • onChange
      • onBlur
      • onFocus


    , FormControl - .
     this.form = new FormGroup<IUserInfo>({ name: new FormControl( this.userInfo.name, [], v => (this.userInfo.name = v) ) }); 

    this.userInfo.name , FormControl . FormControl.for
     this.form = new FormGroup<IUserInfo>({ name: FormControl.for(this.userInfo, 'name', []) }); 

    , name name . , TypeScript, name , . userInfo — .

    — . :)

    Ejemplo


    React TypeScript mobx.
    .
    npm install @quantumart/mobx-form-validation-kit

    ,
    :

    ,
    npm init –y
    npm install --save-dev webpack webpack-cli
    npm install --save react react-dom
    npm install --save-dev @types/react @types/react-dom
    npm install --save-dev typescript ts-loader source-map-loader


    tsconfig.json
     { "compilerOptions": { "outDir": "./dist/", "sourceMap": true, "noImplicitAny": true, "module": "commonjs", "target": "es6", "jsx": "react", "experimentalDecorators": true, "emitDecoratorMetadata": true } } 


    • src\components\Hello.tsx
    • src\index.tsx
    • index.html
    • src\assets\global.scss


    src\components\ Hello.tsx
     import * as React from "react"; export class Hello extends React.Component { render() { return ( <h1> Hello from TypeScript and React! </h1> ); } } 

    src\ index.tsx
     import * as React from "react"; import * as ReactDOM from "react-dom"; import { Hello } from "./components/Hello"; ReactDOM.render( <Hello />, document.getElementById("example") ); 

    index.html
     <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Hello React!</title> </head> <body> <div id="example"></div> <!-- Dependencies --> <script src="./node_modules/react/umd/react.development.js"></script> <script src="./node_modules/react-dom/umd/react-dom.development.js"></script> <!-- Main --> <script src="./dist/main.js"></script> </body> </html> src\assets\global.scss .row { display: inline; } 



    webpack-dev-server
    npm install --save-dev webpack-dev-server
    npm install --save-dev awesome-typescript-loader
    npm install --save-dev html-webpack-plugin

    webpack.config.js
     const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.tsx', resolve: { extensions: ['.ts', '.tsx', '.js'] }, output: { path: path.join(__dirname, '/dist'), filename: 'bundle.min.js' }, module: { rules: [ { test: /\.tsx?$/, loader: 'awesome-typescript-loader' }, { test: /\.(scss|css)?$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { importLoaders: 1, }, }, { loader: 'sass-loader', options: { sourceMap: true } }, ], }, ] }, plugins: [ new HtmlWebpackPlugin({ template: './index.html' }) ] } 

    , mobx React.
     "mobx": "4", "mobx-react": "^6.1.1", 

    C IE10 mobx, 4 , package.json.

      "style-loader": "^0.23.1", "css-loader": "^3.1.0", "node-sass": "^4.12.0", "sass-loader": "^7.1.0" 


    npm install

    , .
    npm install @quantumart/mobx-form-validation-kit



    package.json
     { "name": "ttt", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "webpack-dev-server --mode development --open", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "MIT", "devDependencies": { "@types/react": "^16.9.5", "@types/react-dom": "^16.9.1", "awesome-typescript-loader": "^5.2.1", "html-webpack-plugin": "^3.2.0", "source-map-loader": "^0.2.4", "ts-loader": "^6.2.0", "typescript": "^3.6.3", "webpack": "^4.41.0", "webpack-cli": "^3.3.9" }, "dependencies": { "@quantumart/mobx-form-validation-kit": "^1.0.8", "mobx": "4", "mobx-react": "^6.1.1", "react": "^16.10.2", "react-dom": "^16.10.2", "webpack-dev-server": "^3.8.2", "style-loader": "^0.23.1", "css-loader": "^3.1.0", "node-sass": "^4.12.0", "sass-loader": "^7.1.0" } } 


    npm run start


    Hello from TypeScript and React!


    Hello . RegistrationStore RegistrationStore.ts
    src\RegistrationStore.ts
     import { observable } from "mobx"; export class RegistrationStore { @observable public userInfo = { name: "" }; } export const registrationStore = new RegistrationStore(); 

    Hello.ts, .
     import * as React from "react"; import { observer } from "mobx-react"; import { registrationStore } from "../RegistrationStore"; @observer export class Hello extends React.Component { private changeName = (event: React.ChangeEvent<HTMLInputElement>) => { registrationStore.userInfo.name = event.target.value; }; render() { return ( <React.Fragment> <h1>, {registrationStore.userInfo.name}</h1> <div className="row"> <span>:</span> <input type="text" value={registrationStore.userInfo.name} onChange={this.changeName} /> </div> </React.Fragment> ); } } 

    , Store Mobx. input.
    , . , . «» . , .

    @quantumart/mobx-form-validation-kit

    - .
    stc/ErrorWraper.tsx
     import * as React from "react"; import { observer } from "mobx-react"; import { FormControl } from "@quantumart/mobx-form-validation-kit"; interface Props { formControl: FormControl; } @observer export class ErrorWraper extends React.Component<Props> { render() { return ( <div> {this.props.children} {this.props.formControl.errors.map(error => ( <span key={error.message} className="error"> {error.message} </span> ))} </div> ); } } 

    , -, .

    Hello.tsx .
    - — changeName. {...InputFormControl.bindActions(controls.name)} . .
    - – input, input , , , .
    - – form store , , , componentWillUnmount registrationStore.form.dispose() . mobx FromControl .
     import * as React from "react"; import { observer } from "mobx-react"; import { registrationStore } from "../RegistrationStore"; import { ErrorWraper } from "../ErrorWraper"; import { InputFormControl } from "@quantumart/mobx-form-validation-kit"; @observer export class Hello extends React.Component { constructor(props: any) { super(props); registrationStore.initForm(); } componentWillUnmount() { registrationStore.form.dispose(); } render() { const controls = registrationStore.form.controls; return ( <React.Fragment> <h1>, {registrationStore.userInfo.name}</h1> <div className="row"> <span>:</span> <ErrorWraper formControl={controls.name}> <input type="text" {...InputFormControl.bindActions(controls.name)} /> </ErrorWraper> </div> </React.Fragment> ); } } 

    RegistrationStore.ts.
    .
    ( ) userInfo, form. - userInfo.
     import { observable } from "mobx"; import { FormControl, FormGroup, AbstractControls } from "@quantumart/mobx-form-validation-kit"; interface IUserInfo extends AbstractControls { name: FormControl; } export class RegistrationStore { @observable public userInfo = { name: "" }; @observable public form: FormGroup<IUserInfo>; public initForm(): void { this.form = new FormGroup<IUserInfo>({ name: new FormControl( this.userInfo.name, [], v => (this.userInfo.name = v) ) }); } } export const registrationStore = new RegistrationStore(); 

Source: https://habr.com/ru/post/470537/


All Articles