Mobx上React的新验证包@ QuantumArt / Mobx-form-validation-kit

下午好
今天,我想谈谈基于ReactMobx并以Typescript编写的项目中用于异步验证的新程序包。
当在站点上填写文档,调查表和贷款文档,付款单,注册页面的页面时,Modern Frontend开发涉及大量逻辑。 逻辑检查的主要逻辑负担。 Angular开发人员考虑了这一点,并为此目的向开发人员提供了使用内置的FormControl机制,该机制虽然有很多缺点,但仍然比在React上完全没有这种解决方案要好。 由于React开发的当前趋势涉及使用mobx来组织业务逻辑,因此情况变得复杂。
面对这些问题,我们通过编写一个程序包解决了所有这些问题: @ quantumart / mobx-form-validation-kit

套餐优势:
  • 完全基于TypeScript
  • 与Mobx兼容(版本4,该版本支持每个人都喜欢的IE10)
  • 设计用于React (可以在没有React的项目中使用)
  • 专为异步验证而设计
  • 易于嵌入到现有项目中。

切割后使用包装的说明。


首先,我们将描述@ quantumart / mobx-form-validation-kit程序包的功能,在本文的结尾,我们将编写一个完整的工作页面,并在网站上提供注册表格的示例。

形式控制


@ QuantumArt / mobx-form-validation-kit允许您在源数据和要显示的表单之间创建一个图层。 反过来,它允许您验证它们,并在必要时更改数据,然后再将其移到原始对象。

@ quantumart / mobx-form-validation-kit库包含用于管理表单的三个主要类(验证组件):
  • FormGroup-允许您将验证组件组合在一起。 键入该类,并允许您使用字段列表作为通用参数来重新制作接口。 Any是默认注册的,强烈建议不要在未键入的情况下使用它,但是有可能。
  • FormControl-用于验证特定字段,最常用的类。 该类是类型化的,并将应存储的变量类型作为通用参数。 默认情况下,已注册字符串,因为 默认值为字符串,是表单的最私有选项。
  • FormArray-允许您创建和管理一系列验证组件。

此外,还有基本的抽象类
  • AbstractControl-所有列出的验证类的基类,未键入。
  • FormAbstractControl - FormGroupFormArray的基类,未键入。
  • FormAbstractGroup-不是FormControl的类型化基类,它包含指向正在呈现的html元素的链接。

创建验证表单的最佳实践是以下想法。
在窗体上创建一个类型为FormGroup的对象,并且该字段中已经列出了字段
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支持嵌套,即
 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) ), // … }) // … }); 

您可以添加FormArray ,然后可以将其传递给FormControl类型或整个FormGroup,以创建任何复杂性和结构的对象。
  • FormArray <FormControl>
    FormArray <FormGroup>

    FormControl本身将以下参数集带入构造函数
    • value :TEntity是键入的初始值。
    • 验证程序 :ValidatorFunctionFormControlHandler []-一组验证程序。
    • callbackValidValue :UpdateValidValueHandler | null-最后一个有效值传递给的回调函数。 每当FormControl中的值更改并且该值通过所描述的验证时,都会调用此方法。
    • 激活 :(()=>布尔值)| null-函数将按条件启用/禁用验证(默认情况下始终启用)。 例如,如果未选中“无限制”复选框,则无需检查服务结束日期的有效性。 因此,只需在此处输入一个函数,检查负责“无限制”复选框的可观察字段的状态,就可以自动关闭与该字段关联的所有验证以检查日期,而不是在每个日期字段验证中注册此逻辑。
    • AdditionalData:TAdditionalData | null-包含附加信息的块使您可以将附加信息添加到特定的FormControl ,并在以后使用它们,例如进行可视化。 如果有一些FormControl生成器 ,您需要在其中解析某些信息,而又不通过复杂的数据包将这些信息传递给控件以进行可视化,这将非常方便。 尽管我无法给出确切且不可否认的应用方案,但是拥有这样的机会总比没有机会受苦更好。

    Angular FormControl也有一个限制;不需要在不同的表单上重用对象。 即 您可以创建FormGroup 构建器,并在每个页面上创建自己的对象。 但是,每页页面只能使用一个对象是不好的做法。
    而且, FormControl用单个值初始化,并且如果更改此值,则新值将不会进入FormControl 。 这样做是有目的的,因为如实践所示,由于某种原因,每个人都顽固地尝试绕过验证而不是FormControl中的值来最初编辑原始对象。 只需将新值分配给FormControlvalue字段即可修改原始对象。
    FormGroup在构造函数中接受以下参数集:
    • controls :TControls-从AbstractControls继承的对象。 实际上,只需创建一个继承自AbstractControls接口 ,即可在其中枚举FormGroupFormControlFormArray类型的字段。 您当然可以将类型设置为any ,但是TypeScript的所有优点都将丢失。
    • 验证程序 :ValidatorFunctionFormGroupHandler []-组值的一组验证程序。 例如,您可以为期间选择控件创建一个包含两个值的FormGroup-最小和最大日期。 您将需要在这些验证器中传递检查日期范围的一个或多个功能。 例如,开始日期不大于结束日期
    • 激活 :(()=>布尔值)| null-函数将按条件启用/禁用验证(默认情况下始终启用)。 必须理解,将验证功能应用于某个组会在整个组级别禁用验证。 例如,我们有一个身份证明文件的选择框。 您可以使用不同的字段集创建多个FormGroups :护照,驾驶执照,水手护照等。...在此功能中,检查下拉列表值,如果所选值与该组不对应,则禁用所有验证检查。 更准确地说,无论组中的值如何,该组都将被视为有效。

    让我们谈谈FormControl字段,包括FormGroupFormArray的存在。
    • ControlTypes-控件类型(Control | Group | Array)
    • processing :布尔值-在分析过程中。 因为 支持异步验证,例如,需要服务器请求的异步验证。 扫描的当前状态可以在此字段中找到。
      此外, FormGroupFormArray支持wait方法,该方法允许您等待检查完成。 例如,当您单击“发送数据”按钮时,您需要注册以下设计。
       await this.form.wait(); if (this.form.invalid) { … 

    • disable :布尔值- 禁用错误检查(控件始终有效)
    • active :布尔值-启用错误检查。 取决于激活功能的结果。 使用此值可以非常方便地隐藏表单上的一组字段,而不编写业务逻辑的附加和重复功能。
    • 无效 :布尔值; -对于FormControl-表示该字段包含验证错误。 对于FormGroupFormArray,这意味着组控件本身包含错误,或者其中一个嵌套字段(在任何嵌套级别)都包含验证错误。 即 要检查整个表单的有效性,对上层FormGroup进行一次无效或有效检查就足够了。
    • 有效 :布尔值-对于FormControl-表示该字段不包含验证错误。 对于FormGroup和FormArray,这意味着组控件本身不包含错误,并且任何嵌套字段(在任何嵌套级别)都不包含验证错误。
    • pristine :boolean-使用默认值初始化后,该字段中的值未更改。
    • dirty :boolean-使用默认值初始化后,字段中的值已更改。
    • untouched :布尔值-对于FormControl-表示该字段(例如输入)未聚焦。 对于FormGroup和FormArray,意味着没有嵌套的FormControl成为焦点。 该字段中的false值表示不仅已设置焦点,而且已将焦点从该字段中删除。
    • touched :布尔值-对于FormControl-表示该字段(例如输入)处于焦点。 对于FormGroupFormArray ,这意味着嵌套的FormControl之一是焦点。 该字段中的true值表示不仅设置了焦点,还从该字段中删除了焦点。
    • focused :布尔值-对于FormControl-表示字段(例如输入)现在处于焦点。 对于FormGroupFormArray ,这意味着嵌套的FormControl之一现在成为焦点。
    • errors :ValidationEvent []-该字段包含验证错误。 与列出的字段不同,此数组完全包含FormControlFormGroupFormArray的错误 ,即 此控件的错误,并且并非全部嵌套。 影响有效/无效字段
    • 警告 :ValidationEvent []-该字段包含警告消息。 与列出的字段不同,此数组完全包含FormControl或FormGroup或FormArray的错误,即 此控件的消息,但并非所有消息都已附加。 不影响有效/无效字段
    • informationMessages :ValidationEvent []-该字段包含参考消息。 与列出的字段不同,此数组完全包含FormControl或FormGroup或FormArray的错误,即 此控件的消息,但并非所有消息都已附加。 不影响有效/无效字段
    • 成功 :ValidationEvent-该字段包含其他有效性消息。 与列出的字段不同,此数组完全包含FormControl或FormGroup或FormArray的错误,即 此控件的消息,但并非所有消息都已附加。 不影响有效/无效字段
    • maxEventLevel() -字段中当前验证消息的最大级别。
    • 该方法将在下一个优先级中返回一个枚举值。
      1. ValidationEventTypes.Error;
      2. ValidationEventTypes.Warning;
      3. ValidationEventTypes.Info;
      4. ValidationEventTypes.Success;

    • serverErrors :string []-向服务器发送消息后,也是一种在服务器上检查表单有效性的好表格。 结果,服务器可以返回最终形式检查的错误,并且serverErrors数组适用于这些错误。 serverErrors的一项关键功能是,当焦点从分配了服务器错误的字段中丢失时,自动清除验证消息;如果更改了该字段,则也会清除服务器错误。
    • onChange:委托-除了标准的mobx机制- 反应外,您还可以使用委托并向其添加回调函数,当数据更改时调用该函数。
    • setDirty (脏:布尔值):void-该方法将允许您更改原始 / 字段的值
    • setTouched (touched:boolean):void; -该方法将允许您更改未触摸 /已触摸字段的值
    • dispose ():无效; -需要调用componentWillUnmount中负责页面的控件。


    这些是所有控件的公用字段,但是每个控件还具有针对其类型的唯一字段。
    形式控制
    • value-包含字段的当前值。 您也可以为该字段分配一个新值。


    FormGroupFormArray包含
    • 等待 -该方法允许您期望所有(验证)包括嵌套的检查结束
    • allControls() -此方法使您可以获取所有FormControl的完整集合,包括嵌套在不同级别上。 即 实际上,它将一个多级FormGroup对象(也可以包含FormGroup)扩展为一个仅由FormControl组成的大型列表。 如果我们要查找第一个无效元素并将焦点放在该元素上,则需要此功能。
      在这种情况下,代码如下所示:
       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(); } } ... 



    验证方式


    当然,除了允许您使用数据的控件外,我们还需要进行验证。 @quantumart / mobx-form-validation-kit软件包自然包含许多预定义的验证,并且还支持创建自定义的自定义验证。
    为年龄字段设置FormControl验证的示例。
     new FormControl<number>( this.userInfo.age, [required(), minValue(18, "    18 .", ValidationEventTypes.Warning)], v => (this.userInfo.age = v) ) 

    每个具有最新参数的验证都需要:
    • 消息-验证消息。
    • eventType-消息级别。 支持4种消息级别。
      1. 错误-错误
      2. 警告-警告
      3. 信息-信息性消息
      4. 成功-有关有效性的消息。 例如,您可以验证密码确实很复杂。


    该软件包包含以下一组验证:
    • 必填 (...-必填字段
    • notEmptyOrSpaces (...-该字段不为空,不只包含空格。实际上,这是必需的,要考虑到空格的禁止。
    • pattern (regExp:RegExp,...-第一个参数是字段应匹配的正则表达式。如果没有模式匹配,则会生成错误。
    • invertPattern (regExp:RegExp,...-第一个参数是该字段不应该匹配的正则表达式。如果存在模式匹配,则会生成错误。
    • minLength (minlength:number,....-第一个参数是包含在内的文本的最小长度。如果长度小于传输的长度,则会生成错误。
    • maxLength (maxlength:number, ....-第一个参数是包含在内的文本的最大长度。如果长度大于所传输的长度,则会发出错误。
    • absoluteLength (length:number,....-第一个参数是文本的确切长度。如果长度与指定的长度不匹配,则会发出错误。
    • minValue (min:TEntity |(()=> TEntity),...-此验证仅适用于数字和日期。如果该值小于指定的值,则会设置错误。验证的特殊性是不仅可以接受特定值,而且还可以接受函数,这意味着,如果您从对象的@observable字段读取此函数中的值,则不仅在更改挂起验证的字段时,而且在更改“链接字段”时,都将重新启动验证本身。 第一除外,其被读取为值@observable标记字段。
    • maxValue (max:TEntity |(()=> TEntity),...-此验证仅适用于数字和日期。如果该值大于指定的值,则会设置错误。验证功能是不仅可以接受特定值,而且还可以接受函数,这意味着,如果您从对象的@observable字段读取此函数中的值,则不仅在更改挂起验证的字段时,而且在更改“链接字段”时,都将重新启动验证本身。 第一除标签字段,其被读取为值@observable
    • notContainSpaces (...-与notEmptyOrSpaces不同,如果该值甚至包含至少一个空格,将发出错误。
    • compare (expression:(value:TEntity)=> boolean(...-编写自己的验证函数会生成很多复制粘贴代码,开发此包装程序是为了解决此问题。此验证函数接受一个函数作为第一个参数,该参数继而传递当前值字段,您可以进行复杂的检查,例如,计算TIN或护照号码的哈希值,然后返回true / false;如果检查返回false,则会显示错误。
    • isEqual (value:string ...-一个简单的字符串匹配检查。

    下面介绍了控制验证触发器流程的包装器函数。
    应当注意,传递给FormControlFormGroupFormArray的验证集在单个数组中启动的,实际上没有执行序列。 作为工作的结果,我们将在字段errorswarningsinformationMessages ,由错误,warnings组成的成功数组中组合成单个数组等。
    客户通常只希望看到一个错误,而不是一次看到所有错误。 而且,可以设计TOR,以便仅在前一个检查通过之后才执行检查。
    为了解决此问题,使用wrapperSequentialCheck 。 它的调用及其应用与通常的功能验证器没有什么不同,但是在输入端它会接收到一系列验证器,这些验证器将顺序启动,即 下一个验证仅在前一个通过且没有错误的情况下开始。
    第二个包装器功能是验证的流控制功能。 wrapperActivateValidation作为第一个参数采用一个函数,其中应写入验证激活的条件。 与传递给FormControl的激活函数不同,此检查设计用于更复杂的逻辑。 假设我们有一个用于整个FormGroup付款形式的公共生成器,此外,服务器上只有一种方法可以接受一组公共字段。 但是要注意的是,即使表单是一个表单,我们也会根据“付款类型”向用户显示不同的字段集。 因此wrapperActivateValidation允许编写逻辑,在其中将根据付款类型进行各种检查。
    包装器的使用看起来就像普通函数一样。
     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) ) 

    本示例说明,仅在this.info.A === 10this.info.A === 20的情况下 ,才需要执行()模式(/ \ ^ d {10} $ /) 检查。 ,然后notContainSpaces(),模式(/ \ ^ d {20} $ /)验证将起作用,此外,与第一种情况不同,这些验证将按顺序工作。

    自然,当标准的验证集不再足够的时候到了。
    然后,您必须编写自己的异步函数。 幸运的是,这样做没有任何特殊困难。
    FormControl最初是通过异步验证功能进行优化的,异步验证功能可能希望转到服务器以获取数据,并且此答案需要等待。 结果,所有验证都是异步的。
     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 []; } 

    在这里,您需要注意两个对象。
    首先,我们总是介意数组。 即 实际上,如果愿意,您可以一次返回几条错误消息。
    第二点是返回的对象;它具有以下字段集。
    • key ?:字符串-可选字段,允许您为特定验证指定“密钥”。 对于所有基本键,该键都是唯一的,并且与它们的名称匹配。 您可能想使用key来渲染列表,但是正如实践所示,这是一个坏主意。 将来,在示例中,我将显示使用消息更好,并且完全不触摸按键。 无论如何,就像在Angunar中一样,但实际上它的需求已减少到0。
    • message :字符串-验证消息。 必填字段。
    • type :ValidationEventTypes-消息类型。
      1. 错误-错误
      2. 警告-警告
      3. 信息-信息性消息
      4. 成功-有关有效性的消息。 例如,您可以验证密码确实很复杂。

    • AdditionalData ?:任意-必要时可以与验证一起传输的其他信息。 它可以是一些其他的html标记或特定的样式。 通常,您可以将所有内容放入其中。


    扩展名


    任何魔术都是基于琐碎的事物。 在这种情况下,为了使焦点设置起作用,要从字段中获取更改,需要在特定的输入字段中链接FormControl
    因为 FormControl不会限制开发人员验证数据的类型,因为它的多功能性,有必要在react元素上牺牲一些适用性。
    同时,对于输入和文本区域,可以在一个元素上创建简单的数据绑定功能,对于其他组件,处理器仍将花费最少的精力来替代数据。

    对于输入,元素与FormControl (名称)的绑定将如下所示。
    <input type =“ text” {... InputFormControl.bindActions(controls.name)} />
    对于textarea,绑定将像这样
    <textarea {... TextAreaFormControl.bindActions(controls.name)} />

    InputFormControl.bindActionsTextAreaFormControl.bindActions接受两个参数:
    • formControl :FormControl-实际上是用于绑定的FormControl。 必填项。
    • 事件 ? -可选参数,包含需要定制的函数列表。 , 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 — .

    — . :)

    例子


    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/zh-CN470537/


All Articles