Form
Elemen form HTML bekerja sedikit berbeda dari elemen DOM lainnya di React, karena elemen form secara natural menyimpan beberapa state internal. Sebagai contoh, form ini pada HTML biasa menerima nama tunggal:
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
Form ini memiliki perilaku dasar dari form HTML biasa yakni menuju ke laman baru ketika user mengirim form tersebut. Jika Anda menginginkan perilaku seperti ini di React, ini sebenarnya dapat bekerja. Namun di banyak kasus, akan lebih mudah untuk memiliki sebuah fungsi JavaScript yang menangani sebuah submisi dari sebuah form dan memiliki akses terhadap data yang dimasukkan pengguna ke dalam form. Cara standar untuk mencapai hal ini adalah dengan teknik yang disebut ”controlled component“.
Controlled Component
Pada HTML, elemen form seperti <input>
, <textarea>
, dan <select>
biasanya menyimpan state mereka sendiri dan memperbaruinya berdasarkan masukan dari pengguna. Di React, state yang dapat berubah seperti ini biasanya disimpan pada properti dari komponen, dan hanya akan diubah menggunakan setState()
.
Kita dapat menggabungkan keduanya dengan menggunakan state pada React sebagai “sumber kebenaran satu-satunya”. Kemudian komponen React yang me-render sebuah form juga mengontrol apa yang terjadi dalam form tersebut pada masukan pengguna selanjutnya. Sebuah elemen masukan form yang nilainya dikontrol oleh React melalui cara seperti ini disebut sebagai ”controlled component“.
Sebagai contoh, jika kita ingin membuat form pada contoh sebelumnya mencatat sebuah nama ketika nama dikirim, kita dapat menuliskan form sebagai sebuah controlled component:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) { this.setState({value: event.target.value}); }
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} /> </label>
<input type="submit" value="Submit" />
</form>
);
}
}
Karena atribut value
telah kita set pada elemen form, nilai yang ditampilkan akan selalu sama dengan this.state.value
, yang menjadikan React sebagai sumber kebenaran tunggal dari state. Dan karena handleChange
dijalankan setiap ketikan untuk memperbarui state React, nilai yang ditampilkan akan terbarui ketika pengguna mengetik.
Dengan sebuah controlled component, nilai input akan selalu didorong oleh state di React. Meskipun ini mengharuskan Anda untuk menulis lebih banyak kode, sekarang Anda juga bisa mengoper nilai ini ke elemen antarmuka lain, atau me-reset nilai tersebut dari event handler lain.
Tag textarea
Pada HTML, elemen <textarea>
mendefinisikan teks di dalamnya sebagai elemen anaknya:
<textarea>
Hello there, this is some text in a text area
</textarea>
Di React, <textarea>
menggunakan atribut value
. Dengan cara ini, sebuah form yang menggunakan <textarea>
dapat ditulis dengan cara yang sangat mirip dengan sebuah form yang menggunakan masukan satu baris:
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: 'Please write an essay about your favorite DOM element.' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) { this.setState({value: event.target.value}); }
handleSubmit(event) {
alert('An essay was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Essay:
<textarea value={this.state.value} onChange={this.handleChange} /> </label>
<input type="submit" value="Submit" />
</form>
);
}
}
Perhatikan bahwa this.state.value
diinisialisasi di constructor, sehingga area teks akan memiliki teks di dalamnya.
Tag select
Pada HTML, <select>
membuat sebuah daftar drop-down. Sebagai contoh, HTML ini membuat sebuah daftar drop-down dari beberapa bumbu:
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
Perhatikan bahwa opsi Coconut mula-mula dipilih, karena adanya atribut selected
. Di React, alih-alih menggunakan atribut selected
, kita menggunakan atribut value
di tag select
. Hal ini lebih mudah dalam sebuah controlled component karena Anda hanya perlu mengubahnya di satu tempat saja. Sebagai contoh:
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: 'coconut'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) { this.setState({value: event.target.value}); }
handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite flavor:
<select value={this.state.value} onChange={this.handleChange}> <option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Secara keseluruhan, perubahan-perubahan ini membuat <input type="text">
, <textarea>
, dan <select>
bekerja dengan cara yang mirip - mereka masing-masing menerima atribut value
yang dapat Anda gunakan untuk mengimplementasikan controlled component.
Catatan
Anda bisa memasukan array ke atribut
value
, yang memungkinkan Anda memilih beberapa opsi dalam tagselect
:<select multiple={true} value={['B', 'C']}>
Masukkan Tag File
Dalam HTML, sebuah <input type="file">
membiarkan pengguna untuk memilih satu atau lebih berkas dari penyimpanan perangkat mereka untuk diunggah ke sebuah server atau dimanipulasi oleh JavaScript melalui Berkas API.
<input type="file" />
Karena nilai yang dimiliki adalah read-only, ini termasuk ke dalam uncontrolled component di React. Hal ini akan dibahas bersama dengan uncontrolled component lainnya selanjutnya di dokumentasi.
Menangani Banyak Input
Ketika Anda membutuhkan penanganan banyak elemen input
terkontrol, Anda dapat menambahkan atribut name
pada setiap elemen dan membiarkan fungsi handler memilih apa yang harus dilakukan berdasarkan nilai dari event.target.name
.
Sebagai contoh:
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value });
}
render() {
return (
<form>
<label>
Is going:
<input
name="isGoing" type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests" type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
Perhatikan bagaimana kita meggunakan sintaks computed property name ES6 untuk mengubah state dengan key yang sesuai dengan nama dari masukan:
this.setState({
[name]: value});
Kode diatas setara dengan kode ES5 berikut:
var partialState = {};
partialState[name] = value;this.setState(partialState);
Dan juga, karena setState()
secara otomatis menggabungkan state parsial ke state yang sudah ada, kita hanya perlu memanggilnya dengan bagian yang berubah saja.
Mengendalikan Masukkan Nilai Kosong
Menentukan nilai prop pada controlled component mencegah pengguna mengubah masukan kecuali Anda menginginkannya. Jika Anda telah menetapkan nilai value
namun masukan masih dapat diubah, Anda mungkin telah secara tidak sengaja menetapkan value
ke undefined
atau null
.
Kode berikut menunjukkan contoh ini. (Mula-mula masukan terkunci tetapi menjadi dapat diubah setelah jeda singkat.)
ReactDOM.render(<input value="hi" />, mountNode);
setTimeout(function() {
ReactDOM.render(<input value={null} />, mountNode);
}, 1000);
Alternatif dari Controlled Components
Terkadang akan menjadi sulit untuk menggunakan controlled components, karena Anda perlu menulis event handler untuk setiap cara data Anda berubah dan menyalurkan semua masukan state melalui komponen React. Ini dapat menjadi sangat menjengkelkan ketika Anda sedang mengkonversi basis kode yang sudah ada ke React, atau mengintegrasikan sebuah aplikasi React dengan sebuah library bukan-React. Pada situasi seperti ini, Anda mungkin ingin menggunakan uncontrolled components, sebuah teknik alternatif untuk mengimplementasikan masukan form.
Solusi Selengkapnya
Jika Anda mencari solusi komplit termasuk validasi, melacak fields yang dikunjungi, dan menangani pengiriman form, Formik adalah salah satu pilihan populer. Namun, itu dibuat dengan prinsip yang sama dengan controlled components dan pengelolaan state — jadi jangan lalai untuk mempelajarinya.