Membuat Formulir Bereaksi pada tahun 2020

Hai, Habr. Saya mempersembahkan untuk Anda terjemahan artikel "Membuat formulir dalam React in 2020" oleh Kristofer Selbekk

gambar


Bidang input Area teks. Tombol radio dan kotak centang. Berikut adalah beberapa poin utama interaksi yang kami, sebagai pengembang, miliki dengan pengguna kami. Kami menempatkannya di situs, pengguna mengisinya dan jika kami beruntung, maka formulir yang telah diisi datang kepada kami tanpa kesalahan validasi.

Pemrosesan formulir adalah bagian integral dari sejumlah besar aplikasi web, dan ini adalah salah satu hal yang paling baik Bereaksi lakukan. Anda memiliki kebebasan besar untuk membuat dan memproses formulir. Tetapi apakah ada cara yang lebih baik untuk melakukan ini?

Harap perhatikan bahwa dalam semua contoh ini kami akan membuat formulir masuk dengan bidang email dan kata sandi, tetapi metode ini dapat digunakan dengan sebagian besar jenis formulir.

Ingat aturan bentuk yang baik


Meskipun ini tidak terkait langsung dengan topik yang sedang dibahas, saya ingin memastikan bahwa Anda tidak lupa membuat formulir Anda dapat dimengerti oleh semua orang. Tambahkan tag ke bidang input Anda, atur atribut aria yang benar untuk kasus di mana input tidak valid, dan susun konten Anda secara semantik dengan benar. Ini membuatnya mudah untuk menggunakan formulir Anda untuk pengguna dan pengembang.

Mengolah Formulir Menggunakan State Hook


Untuk memulai, mari kita lihat bagaimana saya biasanya bekerja dengan keadaan formulir. Saya menyimpan semua bidang sebagai elemen negara terpisah dan memperbarui semuanya secara terpisah, yang terlihat seperti ini:

function LoginForm() {
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(email, password);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' value={email} onChange={(e) => setEmail(e.target.value)} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' value={password} onChange={(e) => setPassword(e.target.value)} />
      </div>
    </form>
  );
}

Pertama, saya membuat dua bagian terpisah dari negara bagian - nama pengguna dan kata sandi. Kedua variabel ini kemudian ditransfer ke bidang input yang sesuai, menentukan nilai bidang ini. Setiap kali sesuatu dalam suatu bidang berubah, kami yakin akan memperbarui nilai status, menyebabkan redraw aplikasi kami.

Pemrosesan formulir ini berfungsi dengan baik dalam banyak kasus dan sederhana serta mudah digunakan dan dipahami. Namun, agak membosankan untuk menulis konstruksi semacam itu setiap saat.

Membuat kait khusus


Mari kita lakukan sedikit refactoring dan membuat kait kita sendiri, yang akan sedikit meningkatkan kode kita:

const useFormField = (initialValue: string = '') => {
  const [value, setValue] = React.useState(initialValue);
  const onChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value), []);
  return { value, onChange };
};

export function LoginForm() {
  const emailField = useFormField();
  const passwordField = useFormField();

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(emailField.value, passwordField.value);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' {...emailField} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' {...passwordField} />
      </div>
    </form>
  );
}

Kami membuat hook useFormField kustom yang membuat event handler onChange bagi kami, dan juga menyimpan nilai dalam status formulir. Dalam hal ini, kita dapat menggunakan hook kami dengan semua bidang formulir.

Memproses sejumlah besar bidang


Kerugian dari pendekatan ini adalah bahwa ia tidak menskala dengan baik seiring pertumbuhan formulir Anda. Untuk formulir kecil seperti login, ini mungkin bagus, tetapi ketika Anda membuat formulir profil pengguna Anda mungkin perlu meminta banyak informasi! Haruskah kita memanggil pengait kita lagi dan lagi?

Setiap kali saya menghadapi situasi yang sama, saya cenderung untuk menulis kait kustom yang menyimpan semua formulir saya dalam satu fragmen besar. Mungkin terlihat seperti ini:

export function LoginForm() {
  const { formFields, createChangeHandler } = useFormFields({
    email: '',
    password: '',
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(formFields.email, formFields.password);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' value={formFields.email} onChange={createChangeHandler('email')} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' value={formFields.password} onChange={createChangeHandler('password')} />
      </div>
    </form>
  );
}

Dengan hook useFormFields, kita dapat terus menambahkan bidang tanpa menambah kompleksitas pada komponen kita. Kita dapat mengakses semua status formulir di satu tempat, dan kode kita terlihat rapi dan ringkas. Tentu saja, Anda mungkin perlu menggunakan setState untuk beberapa situasi, tetapi untuk sebagian besar bentuk teknik di atas baik-baik saja.

Pendekatan alternatif


Dengan demikian, penanganan keadaan berfungsi dengan baik, dan dalam kebanyakan kasus ini adalah pendekatan yang disukai dalam Bereaksi. Tapi tahukah Anda bahwa ada cara lain? Ternyata peramban secara default memproses keadaan internal formulir, dan kami dapat menggunakannya untuk menyederhanakan kode kami!

Ini formulir yang sama, tetapi memungkinkan browser untuk menangani keadaan formulir:

export function LoginForm() {
  const handleSubmit = (e: React.FormEvent) => {
	e.preventDefault();
	const formData = new FormData(e.target as HTMLFormElement);
	api.login(formData.get('email'), formData.get('password'));
  };
  return (
	<form onSubmit={handleSubmit}>
  	<div>
    	<label htmlFor="email">Email</label>
    	<input
      	type="email"
      	id="email"
      	name="email"
    	/>
  	</div>
  	<div>
    	<label htmlFor="password">Password</label>
    	<input
      	type="password"
      	id="password"
      	name="password"
    	/>
  	</div>
  	<button>Log in</button>
	</form>
  );
}

Lihat betapa mudahnya! Tidak ada satu kait pun yang digunakan, tidak ada pengaturan nilai awal, tidak ada penangan onChange. Bagian terbaiknya adalah bahwa kode masih berfungsi seperti sebelumnya - tetapi bagaimana caranya?

Anda mungkin telah memperhatikan bahwa kami melakukan sesuatu yang sedikit berbeda dalam fungsi handleSubmit. Kami menggunakan API browser bawaan yang disebut FormData. FormData adalah cara yang nyaman (dan didukung dengan baik) untuk mendapatkan nilai dari kolom input kami!

Kami mendapatkan tautan ke formulir di DOM melalui atribut target acara kirim dan membuat instance baru dari kelas FormData. Sekarang kita bisa mendapatkan semua bidang dengan atribut nama mereka dengan memanggil formData.get ("input field name").

Dengan begitu, Anda tidak perlu secara eksplisit menangani kondisi formulir. Jika Anda memerlukan nilai default (misalnya, jika Anda mengubah nilai bidang awal dari database atau penyimpanan lokal), Bereaksi memberi Anda opsi defaultValue yang nyaman untuk ini.

Kapan harus menggunakan setiap pendekatan


Karena formulir merupakan bagian integral dari sebagian besar aplikasi web, penting untuk mengetahui cara menanganinya. Dan Bereaksi memberi Anda banyak cara untuk melakukan ini.
Untuk formulir sederhana yang tidak memerlukan validasi yang ketat (atau yang dapat mengandalkan kontrol validasi form HTML5 ), saya sarankan Anda cukup menggunakan penanganan bawaan yang disediakan DOM kepada kami secara default. Ada beberapa hal yang tidak dapat Anda lakukan (misalnya, secara terprogram mengubah nilai input atau cek waktu nyata), tetapi dalam kasus yang paling sederhana (misalnya, bidang pencarian atau bidang login, seperti ditunjukkan di atas), Anda mungkin akan merasa cocok pendekatan alternatif kami menggunakan API browser.

Saat Anda melakukan pemeriksaan kustom atau Anda memerlukan akses ke beberapa data formulir sebelum mengirimkannya, Anda perlu memproses keadaan secara eksplisit menggunakan komponen yang dikontrol. Anda dapat menggunakan useStateHooks biasa atau membuat kait kustom untuk sedikit menyederhanakan kode Anda.

Perlu dicatat bahwa pengembang Bereaksi merekomendasikan penggunaan komponen yang dikontrol (secara eksplisit menangani keadaan komponen) dalam banyak kasus - karena pendekatan ini memberi Anda lebih banyak fleksibilitas di masa depan. Menurut pendapat saya, pengembang sering mengorbankan kesederhanaan demi fleksibilitas, yang seringkali tidak mereka butuhkan.

Apa pun pendekatan yang Anda putuskan untuk digunakan, Bereaksi pemrosesan formulir tidak pernah semudah sekarang ini. Anda dapat membiarkan browser menangani formulir sederhana, sementara pada saat yang sama secara eksplisit memproses keadaan formulir ketika situasi mengharuskannya. Saya harap metode di atas akan bermanfaat dan membantu Anda memecahkan masalah dengan mengurangi jumlah baris dalam kode Anda.

All Articles