Menggunakan kembali formulir pada Bereaksi

Hai

Kami memiliki panel admin dan banyak formulir di BCS, tetapi di komunitas Bereaksi tidak ada metode yang diterima secara umum - bagaimana merancang mereka untuk digunakan kembali. Panduan Facebook resmi tidak memiliki informasi terperinci tentang cara bekerja dengan formulir dalam kondisi nyata, di mana validasi dan penggunaan kembali diperlukan. Seseorang menggunakan bentuk-redux, formik, bentuk akhir, atau bahkan menulis solusi mereka sendiri.


Dalam artikel ini kami akan menunjukkan salah satu opsi untuk bekerja dengan formulir di Bereaksi. Tumpukan kami akan seperti ini: Bereaksi + formik + naskah. Kami akan menunjukkan:

  • Apa yang harus dilakukan komponen.
  • Konfigurasi, bidang, dan validasi di tingkat alat peraga.
  • Cara membuat formulir dapat digunakan kembali.
  • Optimalisasi renderer.
  • Daripada metode kami tidak nyaman.

Dengan tugas bisnis yang baru, kami belajar bahwa kami perlu membuat 15-20 formulir yang serupa, dan secara hipotesis mungkin ada lebih banyak lagi. Kami memiliki satu formulir dinosaurus di konfigurasi, yang bekerja dengan data dari `store`, mengirim tindakan untuk menyimpan dan mengeksekusi permintaan melalui` sagas`. Dia luar biasa, melakukan nilai bisnis. Tapi itu sudah tidak dapat diperluas dan tidak dapat digunakan kembali, hanya dengan kode yang buruk dan penambahan kruk.

Tugasnya adalah: menulis ulang formulir sehingga dapat digunakan kembali dalam jumlah tak terbatas. Nah, ingat pemrograman fungsional, ia memiliki fungsi murni yang tidak menggunakan data eksternal, dalam kasus kami `redux`, hanya apa yang dikirim dalam argumen (alat peraga).

Dan itulah yang terjadi.

Gagasan komponen kami adalah Anda membuat pembungkus (wadah) dan menuliskan di dalamnya logika bekerja dengan dunia luar (menerima data dari toko Redux dan mengirim tindakan). Untuk ini, komponen kontainer harus dapat menerima beberapa informasi melalui panggilan balik. Seluruh daftar alat peraga bentuk:

interface IFormProps { //          IsSubmitting?: boolean; //     submitText?: string; //    resetText?: string; //       (  ) validateOnChange?: boolean; //     blur'e  (  ) validateOnBlur?: boolean; // ,      . config: IFieldsFormMetaModel[]; //  . fields: FormFields; //    validationSchema: Yup.MidexSchema; //     onSubmit?: () => void; //     reset  onReset?: (e: React.MouseEvent<HTMLElement>) => void; //    onChangeField?: ( e: React.SyntaticEvent<HTMLInputElement, name: string; value: string ) => void; //      +    onChangeFields?: (values: FormFields, prop: { isValid }) => void; } 

Menggunakan Formik


Kami menggunakan komponen <Formik />.

 render() { const { fields, validationSchema, validateOnBlur = true, validateOnChange = true, } = this.props; return ( <Formik initialValues={fields} render={this.renderForm} onSubmit={this.handleSubmitForm} validationSchema={validationSchema} validateOnBlur={validateOnBlur} validateOnChange={validateOnChange} validate={this.validateFormLevel} /> ); } 

Dalam prop'e dari formulir `validate`, kami memanggil metode` this.validateFormLevel`, di mana kami memberikan kesempatan pada komponen kontainer untuk mendapatkan semua bidang yang diubah dan memeriksa apakah mereka valid.

 private validateFormLevel = (values: FormFields) => { const { onChangeFields, validationSchema } = this.props; if (onChangeFields) { validationSchema .validate(values) .then(() => { onChangeFields(values, { isValid: true }); }) .catch(() => { onChangeFields(values, { isValid: false }); }); } } 

Di sini Anda harus memanggil validasi lagi untuk menjelaskan kepada wadah apakah bidang tersebut valid. Saat mengirimkan formulir, kami cukup memanggil prop `onSubmit`:

 private handleSubmitForm = (): void => { const { onSubmit } = this.props; if (onSubmit) { onSubmit(); } } 

Dengan alat peraga 1-5 semuanya harus jelas. Mari beralih ke 'config', 'fields' dan 'validationSchema'.

Alat peraga 'konfigurasi'


 interface IFieldsFormMetaModel { /**   */ sectionName?: string; sectionDescription?: string; fieldsForm?: Array<{ /**    */ name?: string; //          prop 'fields' /**    checked */ checked?: boolean; /** enum,      */ type?: ElementTypes; /**    */ label?: string; /**    */ helperText?: string; /**      */ required?: boolean; /**      */ disabled?: boolean; /**  -    */ minLength?: number; /**            */ initialValue?: IInitialValue; /**      */ selectItems?: ISelectItems[]; //   select, dropdown   }>; } 

Berdasarkan antarmuka ini, kami membuat array objek dan membuat "bagian" -> "bidang bagian" sesuai dengan skema ini. Jadi, kami dapat menampilkan beberapa bidang untuk bagian atau masing-masing bidang sekaligus, jika Anda memerlukan judul dan catatan. Bagaimana cara rendering bekerja, kami akan tunjukkan nanti.
Contoh singkat konfigurasi:

 export const config: IFieldsFormMetaModel[] = [ { sectionName: ' ', fieldsForm: [{ name: 'subject', label: '', type: ElementTypes.Text, }], }, { sectionName: '', sectionDescription: '  ', fieldsForm: [{ name: 'reminder', disabled: true, label: '', type: ElementTypes.CheckBox, checked: true, }], }, ]; 

Berdasarkan data bisnis, nilai untuk kunci `nama` diatur. Nilai yang sama digunakan dalam kunci prop `bidang` untuk mengirimkan nilai asli atau yang diubah untuk format.

Untuk contoh di atas, `bidang` mungkin terlihat seperti ini:

 const fields: SomeBusinessApiFields = { subject: '  ', reminder: 'yes', } 

Untuk validasi, kita harus melewati Skema Yup. Kami memberikan formulir ke formulir dengan alat peraga wadah, menggambarkan interaksi di sana dengan data eksternal, misalnya, permintaan.

Formulir tidak dapat memengaruhi skema dengan cara apa pun, misalnya:

 export const CreateClientSchema: ( props: CreateClientProps, ) => Yup.MixedSchema = (props: CreateClientProps) => Yup.object( { subject: Yup.string(), description: Yup.string(), date: dateSchema, address: addressSchema(props), }, ); 

Pengoptimalan render dan bidang


Untuk rendering, kami membuat peta untuk pencarian cepat dengan kunci. Itu terlihat ringkas dan pencarian lebih cepat daripada dengan `switch`.

 fieldsMap: Record< ElementTypes, ( state: FormikFieldState, handlers: FormikHandlersState, field: IFieldsFormInfo, ) => JSX.Element > = { [ElementTypes.Text]: ( state: FormikFieldState, handlers: FormikHandlersState, field: IFieldsFormInfo ) => { const { values, errors, touched } = state; return ( <FormTextField key={field.name} element={field} handleChange={this.handleChangeField(handlers.setFieldValue, field.name)} handleBlur={handlers.handleBlur} value={values[field.name]} error={touched[field.name] && errors[field.name] || ''} /> ); }, [ElementTypes.TextSearch]: (...) => {...}, [ElementTypes.TextArea]: (...) => {...}, [ElementTypes.Date]: (...) => {...}, [ElementTypes.CheckBox]: (...) => {...}, [ElementTypes.RadioButton]: (...) => {...}, [ElementTypes.Select]: (...) => {...}, }; 

Setiap bidang komponen stateful. Itu terletak di file terpisah dan dibungkus dengan `React.memo`. Semua nilai ditransmisikan melalui alat peraga, melewati `anak`, untuk menghindari renderer yang tidak perlu.

Kesimpulan


Formulir kami tidak ideal, untuk setiap kasus kami harus membuat pembungkus kontainer untuk bekerja dengan data. Simpan di `store`, konversikan dan buat permintaan. Ada pengulangan kode yang ingin Anda singkirkan. Kami mencoba menemukan solusi baru di mana formulir, tergantung pada alat peraga, akan mengambil kunci yang diinginkan dari toko dengan bidang, tindakan, diagram, dan konfigurasi. Dalam salah satu posting berikut, kami akan memberi tahu Anda apa yang terjadi.

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


All Articles