Paket validasi baru untuk Bereaksi pada Mobx @ quantumart / mobx-form-validation-kit

Selamat siang
Hari ini saya ingin berbicara tentang paket baru untuk validasi asinkron dalam proyek yang didasarkan pada Bereaksi , Mobx dan ditulis dalam naskah .
Pengembangan Frontend Modern melibatkan sejumlah besar logika ketika mengisi halaman dengan dokumen, kuesioner dan dokumen untuk pinjaman, pesanan pembayaran, halaman pendaftaran di situs. Beban logis utama jatuh pada pemeriksaan validasi. Pengembang sudut memikirkan hal ini dan menawarkan pengembang untuk menggunakan mekanisme FormControl bawaan untuk tujuan ini, yang, meskipun memiliki sejumlah kelemahan, masih lebih baik daripada tidak adanya solusi seperti pada React . Situasi ini diperumit oleh fakta bahwa tren perkembangan React saat ini melibatkan penggunaan mobx untuk mengatur logika bisnis.
Menghadapi masalah ini, kami menyelesaikan semuanya dengan menulis sebuah paket: @ quantumart / mobx-form-validation-kit

Keuntungan paket:
  • Seluruhnya di TypeScript
  • Kompatibel dengan Mobx (versi 4, yang mendukung, favorit semua orang, IE10)
  • Dirancang untuk bekerja dalam React (dapat digunakan dalam proyek tanpa bereaksi)
  • Dirancang untuk validasi asinkron
  • Mudah ditanamkan dalam proyek yang sudah ada.

Instruksi untuk bekerja dengan paket di bawah potongan.


Pada awalnya kami akan menjelaskan fungsionalitas dari paket kit @ quantumart / mobx-form-validation , di akhir artikel kami akan menulis halaman yang berfungsi penuh dengan contoh formulir pendaftaran di situs.

Kontrol formulir


@ quantumart / mobx-form-validation-kit memungkinkan Anda membuat lapisan antara sumber data dan formulir untuk ditampilkan. Yang, pada gilirannya, memungkinkan Anda untuk memvalidasinya dan, jika perlu, mengubah data sebelum sampai ke objek asli.

Pustaka @ quantumart / mobx-form-validation-kit berisi tiga kelas utama (komponen validasi) untuk mengelola formulir:
  • FormGroup - memungkinkan Anda untuk menggabungkan komponen validasi bersama. Kelas diketik, dan memungkinkan Anda untuk membuat ulang antarmuka dengan daftar bidang sebagai parameter umum. Apa pun terdaftar secara default, sangat disarankan untuk tidak menggunakannya tanpa mengetik, tetapi ada kemungkinan.
  • FormControl - digunakan untuk memvalidasi bidang tertentu, kelas yang paling umum digunakan. Kelas diketik, dan mengambil sebagai generik parameter jenis variabel yang harus disimpan. Secara default, string terdaftar, karena defaultnya adalah string, sebagai opsi paling pribadi untuk formulir.
  • FormArray - memungkinkan Anda untuk membuat dan mengelola berbagai komponen validasi.

Selain itu, ada kelas abstrak dasar
  • AbstractControl - kelas dasar untuk semua kelas validasi yang terdaftar, tidak diketik.
  • FormAbstractControl - kelas dasar untuk FormGroup dan FormArray , tidak diketik.
  • FormAbstractGroup - bukan kelas dasar yang diketik untuk FormControl, berisi tautan ke elemen html yang sedang dirender.

Praktik terbaik untuk membuat formulir validasi adalah gagasan berikut.
Objek tipe satu FormGroup dibuat pada formulir dan bidang sudah terdaftar di dalamnya
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 mendukung bersarang, mis.
 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) ), // … }) // … }); 

Anda bisa menambahkan FormArray , yang pada gilirannya bisa dilewati tipe FormControl dan atau seluruh FormGroup membuat objek kompleksitas dan struktur apa pun.
  • FormArray <FormControl>
    FormArray <FormGroup>

    FormControl sendiri mengambil set parameter berikut ke dalam konstruktor
    • value : TEntity adalah nilai awal yang diketik.
    • validator : ValidatorFunctionFormControlHandler [] - satu set validator.
    • callbackValidValue : UpdateValidValueHandler | null - fungsi panggil balik yang nilai terakhir terakhir dilewatkan. Itu disebut setiap kali nilai di FormControl berubah dan nilai ini melewati validasi yang dijelaskan.
    • aktifkan : (() => boolean) | null - fungsi akan mengaktifkan / menonaktifkan validasi berdasarkan kondisi (selalu diaktifkan secara default). Misalnya, validitas tanggal akhir layanan tidak perlu diperiksa jika kotak centang "Tidak Terbatas" tidak dicentang. Akibatnya, cukup dengan memasukkan fungsi di sini yang memeriksa keadaan bidang yang dapat diamati yang bertanggung jawab atas kotak centang "Tidak Terbatas", Anda dapat secara otomatis mematikan semua validasi yang terkait dengan bidang untuk memeriksa tanggal, daripada mendaftarkan logika ini di masing-masing validasi bidang tanggal.
    • additionalData : TAdditionalData | null - blok dengan informasi tambahan memungkinkan Anda untuk menambahkan informasi tambahan ke FormControl tertentu dan menggunakannya nanti, misalnya, untuk visualisasi. Ini nyaman jika ada pembangun untuk FormControl di mana Anda perlu mengurai informasi tertentu, dan tidak meneruskan informasi ini melalui bundel data yang kompleks ke kontrol untuk visualisasi. Meskipun saya tidak dapat memberikan skenario aplikasi yang tepat dan tidak dapat disangkal, lebih baik memiliki kesempatan seperti itu daripada menderita tanpanya.

    Ada satu batasan yang dimiliki oleh Angular FormControl : tidak perlu menggunakan kembali objek pada formulir yang berbeda. Yaitu Anda bisa membuat pembuat FormGroup dan membuat objek Anda sendiri di setiap halaman. Tetapi menggunakan satu objek per sekelompok halaman adalah praktik yang buruk.
    Selain itu, FormControl diinisialisasi dengan nilai tunggal, dan jika nilai ini diubah, nilai baru tidak akan masuk ke FormControl . Ini dilakukan dengan sengaja, karena, seperti yang telah ditunjukkan oleh praktik, untuk beberapa alasan, semua orang dengan keras kepala berusaha untuk mengedit objek asli dengan melewati validasi, dan bukan nilai di FormControl . Cukup berikan nilai baru ke bidang nilai FormControl untuk memodifikasi objek asli.
    FormGroup menerima set parameter berikut di konstruktor:
    • kontrol : TControls - objek yang diwarisi dari AbstractControls . Bahkan, cukup buat antarmuka yang diwarisi dari AbstractControls di mana Anda menghitung bidang tipe FormGroup , FormControl , FormArray . Anda tentu saja dapat mengatur tipe ke apa saja , tetapi kemudian semua keuntungan dari TypeScript akan hilang.
    • validator : ValidatorFunctionFormGroupHandler [] - satu set validator untuk nilai grup. Misalnya, Anda bisa membuat FormGroup yang berisi dua nilai - tanggal minimum dan maksimum, untuk kontrol pemilihan periode. Di validator inilah Anda harus melewati fungsi / fungsi memeriksa rentang tanggal. Misalnya, tanggal mulai tidak lebih besar dari tanggal akhir
    • aktifkan : (() => boolean) | null - fungsi akan mengaktifkan / menonaktifkan validasi berdasarkan kondisi (selalu diaktifkan secara default). Harus dipahami bahwa menerapkan fungsi validasi ke grup menonaktifkan validasi di level seluruh grup. Misalnya, kami memiliki kotak pilihan untuk dokumen identitas. Anda dapat membuat beberapa FormGroup dengan kumpulan bidang dokumen yang berbeda: paspor, SIM, paspor pelaut, dll. ... Dalam fungsi ini, periksa nilai dropdown, dan jika nilai yang dipilih tidak sesuai dengan grup ini, semua pemeriksaan validasi dinonaktifkan. Lebih tepatnya, grup akan dianggap valid, terlepas dari nilai-nilai di dalamnya.

    Mari kita bicara tentang bidang FormControl , termasuk keberadaan FormGroup dan FormArray .
    • ControlTypes - jenis kontrol (Kontrol | Grup | Array)
    • pemrosesan : boolean - dalam proses analisis. Karena Validasi asinkron didukung, misalnya, yang memerlukan permintaan server. Status pemindaian saat ini dapat ditemukan di bidang ini.
      Selain itu, FormGroup dan FormArray mendukung metode tunggu , yang memungkinkan Anda menunggu pemeriksaan selesai. Misalnya, ketika Anda mengklik tombol "kirim data", Anda harus mendaftarkan desain berikut.
       await this.form.wait(); if (this.form.invalid) { … 

    • dinonaktifkan : boolean - pengecekan kesalahan dinonaktifkan (kontrol selalu valid)
    • aktif : boolean - pengecekan kesalahan diaktifkan. Tergantung pada hasil dari fungsi aktivasi. Nilai ini sangat nyaman digunakan untuk menyembunyikan sekelompok bidang pada formulir dan tidak menulis fungsi logika bisnis tambahan dan duplikat.
    • tidak valid : boolean; - untuk FormControl - berarti bidang tersebut berisi kesalahan validasi. Untuk FormGroup dan FormArray, itu berarti kontrol grup itu sendiri mengandung kesalahan, atau salah satu bidang yang bersarang (pada level bersarang mana saja) mengandung kesalahan validasi. Yaitu untuk memeriksa validitas seluruh formulir, cukup melakukan satu cek yang tidak valid atau valid dari FormGroup atas.
    • valid : boolean - for FormControl - berarti bidang tersebut tidak mengandung kesalahan validasi. Untuk FormGroup dan FormArray, itu berarti kontrol grup itu sendiri tidak mengandung kesalahan dan tidak ada bidang yang bersarang (pada tingkat bersarang apa pun) yang mengandung kesalahan validasi.
    • murni : boolean - nilai di lapangan, setelah inisialisasi dengan nilai default, tidak berubah.
    • kotor : boolean - nilai di lapangan, setelah inisialisasi dengan nilai default, berubah.
    • tak tersentuh : boolean - untuk FormControl - berarti bidang (mis. input) tidak dalam fokus. Untuk FormGroup dan FormArray berarti bahwa tidak ada FormControl yang bersarang dalam fokus. Nilai false di bidang ini berarti bahwa fokus tidak hanya ditetapkan, tetapi juga dihapus dari bidang.
    • menyentuh : boolean - Untuk FormControl - berarti bidang (misalnya, input) dalam fokus. Untuk FormGroup dan FormArray , itu berarti salah satu FormControls bersarang berada dalam fokus. Nilai true dalam bidang ini berarti bahwa fokus tidak hanya ditetapkan, tetapi juga dihapus dari bidang.
    • terfokus : boolean - untuk FormControl - berarti bidang tersebut (misalnya input) sekarang dalam fokus. Untuk FormGroup dan FormArray , itu berarti bahwa salah satu FormControls bersarang sekarang dalam fokus.
    • kesalahan : ValidationEvent [] - bidang berisi kesalahan validasi. Tidak seperti bidang yang terdaftar, array ini mengandung kesalahan FormControl , atau FormGroup , atau FormArray , yaitu kesalahan kontrol ini, dan tidak semua bersarang. Mempengaruhi bidang yang valid / tidak valid
    • peringatan : ValidationEvent [] - bidang berisi pesan Peringatan. Tidak seperti bidang yang terdaftar, array ini mengandung kesalahan FormControl, atau FormGroup, atau FormArray, yaitu pesan dari kontrol ini, tetapi tidak semua terlampir. Tidak memengaruhi bidang yang valid / tidak valid
    • informationMessages : ValidationEvent [] - bidang berisi pesan informasi. Tidak seperti bidang yang terdaftar, array ini mengandung kesalahan FormControl, atau FormGroup, atau FormArray, yaitu pesan dari kontrol ini, tetapi tidak semua terlampir. Tidak memengaruhi bidang yang valid / tidak valid
    • sukses : ValidationEvent - bidang berisi pesan validitas tambahan. Tidak seperti bidang yang terdaftar, array ini mengandung kesalahan FormControl, atau FormGroup, atau FormArray, yaitu pesan dari kontrol ini, tetapi tidak semua terlampir. Tidak memengaruhi bidang yang valid / tidak valid
    • maxEventLevel () - tingkat maksimum pesan validasi saat ini di lapangan.
    • Metode akan mengembalikan salah satu nilai enum, dalam prioritas berikutnya.
      1. ValidationEventTypes.Error;
      2. ValidasiEventTypes.Warning;
      3. ValidationEventTypes.Info;
      4. ValidationEventTypes. Berhasil;

    • serverErrors : string [] - setelah mengirim pesan ke server, ada baiknya juga untuk memeriksa validitas formulir di server. Akibatnya, server dapat mengembalikan kesalahan dari pemeriksaan formulir akhir, dan array serverErrors dimaksudkan untuk kesalahan ini. Fitur utama dari serverErrors adalah pembersihan otomatis pesan validasi ketika fokus hilang dari bidang di mana kesalahan server diberikan, dan kesalahan server juga dihapus jika bidang telah diubah.
    • onChange: Delegasi - sebagai tambahan dari mekanisme mobx standar - reaksi, Anda dapat menggunakan delegate dan menambahkan fungsi callback ke dalamnya, yang dipanggil saat data berubah.
    • setDirty (kotor: boolean): void - metode ini akan memungkinkan Anda untuk mengubah nilai dari bidang yang masih asli / kotor
    • setTouched (disentuh: boolean): void; - metode ini akan memungkinkan Anda untuk mengubah nilai bidang yang belum tersentuh / tersentuh
    • buang (): batal; - diperlukan untuk memanggil kontrol yang bertanggung jawab atas halaman di componentWillUnmount.


    Ini adalah bidang yang umum untuk semua kontrol, tetapi setiap kontrol juga memiliki bidang yang unik untuk jenisnya.
    Kontrol formulir
    • nilai - berisi nilai bidang saat ini. Anda juga dapat menetapkan nilai baru untuk bidang ini.


    FormGroup dan FormArray berisi
    • tunggu - metode ini memungkinkan Anda untuk mengharapkan akhir dari semua (validasi) termasuk bersarang
    • allControls () - metode ini memungkinkan Anda untuk mendapatkan satu set lengkap semua FormControl termasuk bersarang di tingkat yang berbeda. Yaitu pada kenyataannya, ia memperluas objek FormGroup multilevel, yang juga bisa berisi FormGroup, menjadi satu daftar besar yang hanya terdiri dari FormControl. Fungsionalitas ini diperlukan jika kami ingin menemukan elemen yang tidak valid pertama dan fokus padanya
      kode, dalam hal ini, akan terlihat seperti ini:
       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(); } } ... 



    Validasi


    Tentu saja, selain kontrol yang memungkinkan Anda bekerja dengan data, kami membutuhkan validasi sendiri. Paket @ quantumart / mobx-form-validation-kit secara alami berisi sejumlah validasi yang telah ditentukan, dan juga mendukung pembuatan validasi kustom.
    Contoh pengaturan validasi untuk FormControl untuk bidang usia.
     new FormControl<number>( this.userInfo.age, [required(), minValue(18, "    18 .", ValidationEventTypes.Warning)], v => (this.userInfo.age = v) ) 

    Setiap validasi dengan parameter terbaru membutuhkan:
    • Pesan - Pesan validasi.
    • eventType - tingkat pesan. 4 tingkat pesan didukung.
      1. Kesalahan - kesalahan
      2. Peringatan - peringatan
      3. Info - Pesan Informasi
      4. Sukses - pesan tentang validitas. Misalnya, Anda dapat memverifikasi bahwa kata sandi itu sangat kompleks.


    Paket berisi set validasi berikut:
    • diperlukan (... - bidang wajib diisi
    • notEmptyOrSpaces (... - bidang tidak kosong dan tidak hanya berisi spasi. Bahkan, diperlukan, dengan mempertimbangkan larangan ruang.
    • pola (regExp: RegExp, ... - parameter pertama adalah ekspresi reguler yang harus cocok dengan bidang. Kesalahan dihasilkan jika tidak ada pencocokan pola.
    • invertPattern (regExp: RegExp, ... - parameter pertama adalah ekspresi reguler yang tidak cocok dengan bidang. Kesalahan dihasilkan jika ada kecocokan pola.
    • minLength (minlength: number, .... - parameter pertama adalah panjang minimum teks inklusif. Kesalahan dihasilkan jika panjangnya kurang dari yang dikirim.
    • maxLength (maxlength: number, .... - parameter pertama adalah panjang maksimum teks inklusif. Kesalahan dikeluarkan jika panjangnya lebih panjang dari yang dikirim.
    • absoluteLength (length: number, .... - parameter pertama adalah panjang teks yang tepat. Kesalahan akan terjadi jika panjangnya tidak cocok dengan yang ditentukan.
    • minValue (min: TEntity | (() => TEntity), ... - validasi ini hanya ditujukan untuk angka dan tanggal. Kesalahan ditetapkan jika nilainya kurang dari yang ditentukan. Keunikan validasi adalah kemampuan untuk menerima tidak hanya nilai tertentu, tetapi juga fungsi, yang berarti bahwa jika Anda membaca nilai dalam fungsi ini dari bidang @observable objek, validasi itu sendiri akan dimulai kembali tidak hanya ketika bidang di mana validasi digantung diubah, tetapi juga ketika "bidang tertaut" diubah. pertama kecuali bidang tag yang dibaca sebagai nilai @observable.
    • maxValue (maks: TEntity | (() => TEntity), ... - validasi ini hanya ditujukan untuk angka dan tanggal. Kesalahan diatur jika nilainya lebih besar dari yang ditentukan. Fitur validasi adalah kemampuan untuk menerima tidak hanya nilai tertentu, tetapi juga fungsi, yang berarti bahwa jika Anda membaca nilai dalam fungsi ini dari bidang @observable objek, validasi itu sendiri akan dimulai kembali tidak hanya ketika bidang di mana validasi digantung diubah, tetapi juga ketika "bidang tertaut" diubah. pertama kecuali bidang tag yang dibaca sebagai nilai @observable
    • notContainSpaces (... - tidak seperti notEmptyOrSpaces, kesalahan akan dikeluarkan jika nilainya bahkan mengandung setidaknya satu spasi.
    • bandingkan (ekspresi: (nilai: TEntity) => boolean (... - menulis fungsi validasi Anda sendiri menghasilkan banyak kode salin-rekat, pembungkus ini dikembangkan untuk menghilangkan masalah ini. Fungsi validasi ini menerima fungsi sebagai parameter pertama, yang pada gilirannya melewati nilai saat ini) bidang, yang memungkinkan Anda untuk membuat pemeriksaan kompleks, misalnya, menghitung hash untuk TIN atau nomor paspor, dan kemudian mengembalikan true / false. Kesalahan akan ditampilkan jika centang mengembalikan false.
    • isEqual (nilai: string ... - cek kecocokan string sederhana.

    Berikut ini menjelaskan fungsi pembungkus yang mengontrol aliran pemicu validasi.
    Perlu dicatat bahwa set validasi diteruskan ke FormControl , FormGroup , FormArray diluncurkan dalam satu array dan pada kenyataannya tidak memiliki urutan eksekusi. Sebagai hasil dari pekerjaan, kita akan memiliki kesalahan di bidang, peringatan , informasi Pesan , array sukses yang terdiri dari kesalahan, peringatan, digabungkan menjadi satu array, dll ...
    Seringkali pelanggan hanya ingin melihat satu kesalahan, dan tidak sekaligus. Selain itu, TOR dapat dirancang sehingga satu pemeriksaan dilakukan hanya setelah yang sebelumnya telah berlalu.
    Untuk mengatasi masalah ini, wrapperSequentialCheck digunakan. Panggilan dan aplikasinya tidak berbeda dari validator fungsi biasa, tetapi pada input itu menerima array validator yang akan diluncurkan secara berurutan, mis. Validasi berikutnya hanya dimulai setelah yang sebelumnya berlalu tanpa kesalahan.
    Fungsi pembungkus kedua adalah fungsi kontrol aliran validasi. wrapperActivateValidation sebagai parameter pertama menerima fungsi di mana perlu untuk mendaftarkan kondisi untuk aktivasi validasi. Berbeda dengan fungsi aktifkan yang diteruskan ke FormControl, pemeriksaan ini dirancang untuk logika yang lebih kompleks. Misalkan kita memiliki pembangun bersama untuk seluruh bentuk pembayaran FormGroup , dan terlebih lagi, hanya ada satu metode di server yang menerima kumpulan bidang yang sama. Tetapi tangkapannya adalah meskipun bentuknya satu, tergantung pada "jenis pembayaran" kami menunjukkan kumpulan bidang yang berbeda kepada pengguna. Jadi wrapperActivateValidation memungkinkan Anda untuk menulis logika di mana berbagai pemeriksaan akan dilakukan tergantung pada jenis pembayaran.
    Penggunaan pembungkus akan terlihat seperti fungsi biasa.
     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) ) 

    Contoh ini menunjukkan bahwa pemeriksaan wajib (), pola (/ \ ^ d {10} $ /) hanya akan dilakukan dengan this.info.A === 10 , dan jika this.info.A === 20 , kemudian notContainSpaces (), validasi pola (/ \ ^ d {20} $ /) akan berfungsi, selain itu, validasi ini akan bekerja secara berurutan, tidak seperti kasus pertama.

    Secara alami, saatnya akan tiba ketika set validasi standar tidak lagi cukup.
    Maka Anda harus menulis fungsi asinkron Anda sendiri. Untungnya, ini dilakukan tanpa kesulitan khusus.
    FormControl awalnya dipertajam oleh fungsi validasi asinkron, yang mungkin ingin pergi ke server untuk data, dan jawaban ini perlu menunggu. Dan sebagai hasilnya, semua validasi tidak sinkron.
     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 []; } 

    Di sini Anda perlu memperhatikan dua objek.
    Pertama, kami selalu memikirkan array. Yaitu bahkan, Anda dapat mengembalikan beberapa pesan kesalahan sekaligus, jika diinginkan.
    Titik kedua adalah objek yang dikembalikan, ia memiliki set bidang berikut.
    • key ?: string - bidang opsional, memungkinkan Anda menentukan "kunci" untuk validasi tertentu. Untuk semua tombol dasar, kunci tersebut unik dan cocok dengan namanya. Anda mungkin ingin menggunakan kunci untuk membuat daftar sebagai reaksi, tetapi seperti yang telah ditunjukkan oleh praktik, ini adalah ide yang buruk. Di masa depan, dalam contoh, saya akan menunjukkan bahwa lebih baik menggunakan pesan, dan tidak menyentuh tombol sama sekali. Bagaimanapun, seperti di Angunar, tetapi kebutuhannya telah berkurang, pada kenyataannya, menjadi 0.
    • message : string - pesan validasi. Bidang wajib.
    • type : ValidationEventTypes - tipe pesan.
      1. Kesalahan - kesalahan
      2. Peringatan - peringatan
      3. Info - Pesan Informasi
      4. Sukses - pesan tentang validitas. Misalnya, Anda dapat memverifikasi bahwa kata sandi itu sangat kompleks.

    • additionalData ?: ada - informasi tambahan yang dapat dikirim bersama dengan validasi, jika perlu. Ini bisa berupa markup html tambahan atau gaya tertentu. Secara umum, Anda bisa memasukkan semuanya ke dalam apa saja.


    Ekstensi


    Sihir apa pun didasarkan pada hal-hal sepele. Dan dalam hal ini, agar pengaturan fokus berfungsi, mendapatkan perubahan dari bidang memerlukan penautan FormControl di bidang input tertentu.
    Karena FormControl tidak membatasi pengembang dalam jenis data yang divalidasi, karena keserbagunaannya, perlu untuk mengorbankan sedikit penerapan pada elemen reaksi.
    Pada saat yang sama, untuk input dan textarea dimungkinkan untuk membuat fungsi sederhana dari pengikatan data ke elemen, untuk komponen lain, prosesor masih harus melakukan upaya minimal untuk mengganti data.

    Untuk input, pengikatan elemen ke FormControl (nama) akan terlihat seperti ini.
    <input type = "text" {... InputFormControl.bindActions (controls.name)} />
    Untuk textarea, mengikat akan seperti ini
    <textarea {... TextAreaFormControl.bindActions (controls.name)} />

    InputFormControl.bindActions dan TextAreaFormControl.bindActions menerima dua parameter:
    • formControl : FormControl - sebenarnya FormControl yang akan digunakan untuk mengikat. Wajib.
    • acara ? - Parameter opsional yang berisi daftar fungsi yang dapat dipanggil jika Anda perlu menyesuaikannya. , 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 β€” .

    β€” . :)

    Contoh


    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/id470537/


All Articles