Forms in React
本文介紹如何在 React 中使用 Forms 表單相關元素。
Controlled Components
在 HTML 中,表單 (Forms) 裡面的項目像是 Input、Textarea、Select 會自動跟著使用者輸入的值而改變狀態,而在 React 中,狀態則是透過 setState()
來更新,屬於單向資料流。
因此,當我們在 React 使用 Input 時,就要一起把 State 與 Input 的 value
屬性做綁定,這麼一來 Input 的值又會是透過 React 控制了。此時,這樣的元件又被稱作 Controlled Components,很重要,記得要綁定!
表單範例:Input、Textarea、Checkbox
可以看到 Input, Textarea 的 value
都被我們綁上了 React 的 State,還有 Checkbox 的 checked
屬性也是。
現在這些表單的值都會等於 React 的 State,因此我們透過 onChange
事件去更改 State,並且監聽每一個 Keystroke 隨時更新表單呈現的值。
除此之外,這裡的 handleChange
有幾個小巧思,可以特別留意一下:
- 回傳時,我們使用 Spread 來把原物件展開,再添加新的 Key-value Pair
- 所有表單元素都有
name
屬性用來聲明欄位名稱,我們使用 ES6 的 Computed Property 來動態取得name
,藉由它來當作新的物件的 Key - 透過三元判斷,去判斷
type
是否為 Checkbox,因為只有 Checkbox 需要的值是checked
(Boolean) 而非value
(String)
1import React from 'react'; 2 3const Form = () => { 4 const [formData, setFormData] = React.useState({ 5 firstName: '', 6 lastName: '', 7 email: '', 8 comments: '', 9 isFriendly: true, 10 }); 11 12 const handleChange = (event) => { 13 const { name, value, type, checked } = event.target; 14 setFormData((prevFormData) => { 15 return { 16 ...prevFormData, 17 [name]: type === 'checkbox' ? checked : value, 18 }; 19 }); 20 }; 21 22 return ( 23 <form> 24 <input 25 type="text" 26 placeholder="First Name" 27 onChange={handleChange} 28 name="firstName" 29 value={formData.firstName} 30 /> 31 <input 32 type="text" 33 placeholder="Last Name" 34 onChange={handleChange} 35 name="lastName" 36 value={formData.lastName} 37 /> 38 <input 39 type="email" 40 placeholder="Email" 41 onChange={handleChange} 42 name="email" 43 value={formData.email} 44 /> 45 <textarea 46 value={formData.comments} 47 placeholder="Comments" 48 onChange={handleChange} 49 name="comments" 50 /> 51 <input 52 type="checkbox" 53 id="isFriendly" 54 checked={formData.isFriendly} 55 onChange={handleChange} 56 name="isFriendly" 57 /> 58 <label htmlFor="isFriendly">Are you friendly?</label> 59 <br /> 60 </form> 61 ); 62}; 63 64export default Form; 65
表單範例:Radio
製作 React 表單的 Radio 時,我們可以對 checked
屬性判斷 formData.employment
是否等於選取到的 value
,以呈現哪一個選項是被選取的。
1import React from 'react'; 2 3const Form = () => { 4 const [formData, setFormData] = React.useState({ 5 firstName: '', 6 lastName: '', 7 email: '', 8 comments: '', 9 isFriendly: true, 10 employment: '', 11 }); 12 console.log(formData.employment); 13 14 const handleChange = (event) => { 15 const { name, value, type, checked } = event.target; 16 setFormData((prevFormData) => { 17 return { 18 ...prevFormData, 19 [name]: type === 'checkbox' ? checked : value, 20 }; 21 }); 22 }; 23 24 return ( 25 <form> 26 <fieldset> 27 <legend>Current employment status</legend> 28 29 <input 30 type="radio" 31 id="unemployed" 32 name="employment" 33 value="unemployed" 34 checked={formData.employment === 'unemployed'} 35 onChange={handleChange} 36 /> 37 <label htmlFor="unemployed">Unemployed</label> 38 <br /> 39 40 <input 41 type="radio" 42 id="part-time" 43 name="employment" 44 value="part-time" 45 checked={formData.employment === 'part-time'} 46 onChange={handleChange} 47 /> 48 <label htmlFor="part-time">Part-time</label> 49 <br /> 50 51 <input 52 type="radio" 53 id="full-time" 54 name="employment" 55 value="full-time" 56 checked={formData.employment === 'full-time'} 57 onChange={handleChange} 58 /> 59 <label htmlFor="full-time">Full-time</label> 60 <br /> 61 </fieldset> 62 </form> 63 ); 64}; 65 66export default Form; 67
表單範例:Select & Option
在 HTML 中 Select 與 Option 會透過 selected
屬性標註被選取到的選項,例如:
1<select> 2 <option selected value="seal">Seal</option> 3</select> 4
但是在 React 中,因為我們要控制狀態,所以必須想辦法把 State 綁定上去。
我們新增狀態 favColor
把它綁定到 <select>
的 value
屬性上,並且透過 onChange
事件更新狀態。
1const [formData, setFormData] = React.useState({ 2 firstName: '', 3 lastName: '', 4 email: '', 5 comments: '', 6 isFriendly: true, 7 employment: '', 8 favColor: '', 9}); 10console.log(formData.favColor); 11
跟其他範例一樣新增 HTML name
屬性,用 ES6 Computed Property 作為 setState
更新的 key
,另外也新增了空值的預設選項。
1<select 2 id="favColor" 3 value={formData.favColor} 4 onChange={handleChange} 5 name="favColor" 6> 7 <option value="">-- Choose --</option> 8 <option value="red">Red</option> 9 <option value="orange">Orange</option> 10 <option value="yellow">Yellow</option> 11 <option value="green">Green</option> 12 <option value="blue">Blue</option> 13 <option value="indigo">Indigo</option> 14 <option value="violet">Violet</option> 15</select> 16
最後來送出表單吧
在 HTML 中,如果在 <form>
裡面放 <button>
預設就會是 type="submit"
,網頁會透過這個按鈕去送出表單。
1<form method="POST" action="somePhp.php"> 2 <button>Submit</button> 3</form> 4
以下則是我們在 React 送出表單的做法,我們透過 Submit Button (Default type in form) 去觸發 onSumbit
事件來監聽表單送出,然後執行我們自訂的函式。
1<form onSubmit="handleSubmit"> 2 <button>Submit</button> 3</form> 4
然而,如果表單沒有寫 action
的話,默認 HTML 會重整頁面,並且在網址後面加一段 Query String 例如:
/index.html?firstName=Sean&lastName=Huang&email=&comments=&isFriendly=on&favColor=red
這是預設的行為,但是我們在 React 當然不想這麼做,所以這裡先加個 event.preventDefault()
阻止預設行為,然後再呼叫 API 送表單資料給後端。
1function handleSubmit() { 2 event.preventDefault(); 3 submitToApi(formData); 4} 5
Recap
- Event listeners
- State
- Conditional rendering
- Forms