在上個章節中,我們學習到了在 React 中可以如何處理 form element 的兩種方式:
也知道了 controlled component 的使用情境有以下幾種:
接下來就來詳細介紹 controlled component 的語法吧!
如上個章節所述,controlled component 的使用重點就在於:
onChange
propsetState
更新 value 的值然而每個 form element 用來設定 value 的 prop 與取得使用者輸入值的方式不盡相同,因此下面將一一介紹各 element 的 value prop、onChange
、取得使用者輸入值的方式以及其用法。
Text input controlled component 的語法重點如下:
value
onChange
prop:onChange
event.target.value
讓我們來看看使用範例:
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>
);
}
}
使用者也可以到 CodePen 上實際試試。
這個範例可以輸入名字,按下 submit
後名字就會透過 alert
顯示到畫面上。
可以看到程式中,value={this.state.value}
被設定在 input element 上,也就是 input element 的顯示值會一直等同於 this.state.value
。
接著,當使用者輸入任何字元時,都會觸發 onChange
的 handler:this.handleChange
。
this.handleChange
中會執行 setState
把使用者輸入的內容:event.target.value
更新到 this.state.value
上,使用者因此可以看到 input 上顯示自己剛剛輸入的值。
最後,當 input 按下 submit 時,就會觸發 form 的 onSubmit={this.handleSubmit}
並用 alert 將使用者的名字顯示到畫面上。
Checkbox input controlled component 的語法重點如下:
checked
onChange
prop:onChange
event.target.checked
或 event.target.value
較特別的地方是,checkbox 使用 event.target.checked
或 event.target.value
都可以拿到使用者輸入的新值。
使用 event.target.checked
拿到的會是 Boolean,代表使用者勾選與否。通常會在 input 中加上 name
prop 以取得 event.target.name
來設定對應的 state 內容:
class SkillForm extends React.Component {
constructor(props) {
super(props);
this.state = { React: false, Vue: false, Angular: false };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.name]: event.target.checked });
}
// ...
render() {
return (
//...
<input
type="checkbox"
name="React"
checked={this.state.React}
onChange={this.handleChange}
/>
}
}
使用者可以到 CodePen 查看範例。
而使用 event.target.value
拿到的會是 String,代表使用者勾選選項的值。這個作法需要在 input 中加上 value
prop 來設定對應的 state 內容。
使用方式與 event.target.checked
大同小異,讀者可以查看這個 CodePen 範例。
以上兩個做法都是可行的,讀者可視當下的使用情境決定要用哪個作法。
Radio input controlled component 的語法重點如下:
checked
onChange
prop:onChange
event.target.checked
或 event.target.value
與 type=checkbox
相同,input
type=radio
使用 event.target.checked
或 event.target.value
都可以拿到使用者輸入的新值。
使用 event.target.checked
拿到的會是 Boolean,代表使用者勾選與否:
radio 與 checkbox 相同,使用 event.target.checked
或 event.target.value
都可以拿到使用者輸入的新值。
使用 event.target.checked
拿到的會是 Boolean,代表使用者勾選與否。通常會在 input 中加上 name
prop 以取得 event.target.name
來設定對應的 state 內容:
class GenderForm extends React.Component {
constructor(props) {
super(props);
this.state = { gender: "" };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ gender: event.target.name });
}
// ...
render() {
return (
// ...
<input
type="radio"
name="Male"
checked={this.state.gender === "Male"}
onChange={this.handleChange}
/>
);
}
}
使用者可以到 CodePen 查看範例。
而使用 event.target.value
拿到的會是 String,代表使用者勾選選項的值。這個作法需要在 input 中加上 value
prop 來設定對應的 state 內容。
使用方式與 event.target.checked
大同小異,讀者可以查看這個 CodePen 範例。
以上兩個做法都是可行的,讀者可視當下的使用情境決定要用哪個作法。
Textarea controlled component 的語法重點如下:
value
onChange
prop:onChange
event.target.value
在 HTML 中,textarea
是以 children 定義預設內容:
<!-- HTML textarea -->
<textarea>
Hello there, this is some text in a text area
</textarea>
JSX 的 textarea
為了與 input text 的 prop api 統一,則是使用 value
作為設定輸入內容的 prop:
// JSX controlled textarea
<textarea value={this.state.value} onChange={this.handleChange} />
讀者也可以到 CodePen 上查看完整範例。
Select controlled component 的語法重點如下:
value
(內容為 option
的 value)onChange
prop:onChange
event.target.value
在 HTML 中,select
定義預設選定內容的方式是在 children 的目標 option
中加上 selected
prop:
<!-- HTML select -->
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
在 JSX 中,則是在 select
中加上 value
prop 來設定輸入內容,這樣就只需要更新一個地方就可以控制所有 option
的選取與否。另外,也能與 input text 的 prop api 統一格式:
// JSX controlled select
<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>
讀者也可以到 CodePen 上查看完整範例。
這篇教學文將每個 form element 的 value prop / onChange / 使用者輸入的新值整理成了一個淺顯易懂的表格,讀者應該會覺得很有幫助:
Form element | value prop | onChange prop | 使用者輸入的新值 |
---|---|---|---|
<input type="text" /> |
value="string" |
onChange |
event.target.value |
<input type="checkbox" /> |
checked={boolean} |
onChange |
event.target.checked 或 event.target.value |
<input type="radio" /> |
checked={boolean} |
onChange |
event.target.checked 或 event.target.value |
<textarea /> |
value="string" |
onChange |
event.target.value |
<select /> |
value="option value" |
onChange |
event.target.value |
需要注意的是,只要 form element 只要設定了 value prop 就算是 controlled component 了。React 會把 input 的內容設定為 value 的值。
然而不同時設定 onChange
的話,controlled component 的值就會永遠被固定住無法被使用者輸入改變,如下所示:
// This input in uneditable
<input value="uneditable" />
因此正常來講 value 跟 onChange
prop 都要同時設定。
Nil
時可正常輸入一個 controlled component 的特例是,如果 value 是 Nil
( null
或 undefined
)的話,該 component 就會變成 uncontrolled component,React 就不會控制其輸入內容。使用者輸入的內容會不經過 React 的掌控顯示到畫面上,範例如下:
// The bellow two inputs are all editable
<input />
<input value={undefined} />
<input value={null} />
// Warning: value prop on input should not be null. Consider using an empty string to clear the component or undefined for uncontrolled components.
這時使用者可以自由輸入內容。而 React 也會顯示 value
不應該是 null 的警告。
還記得前面段落提到的,controlled component 的內容是與 React component state 同步的。
也就是說,無論何時設定 state,其內容都會顯示到 form 上。
我們可以利用這個特性,在 component 初始化時,將 this.state
的值時設定為要 form 預設顯示的內容。Form 就會因此在一 mount 起來時就帶有預設值。
舉例來說,如果要用 textarea
做一個簡單的作文輸入器,而這個 textarea
要有預設值:
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>
);
}
}
使用者可以到 CodePen 上查看完整範例。
範例中在 constructor
中初始 this.state
的 value
,並將 textarea
的 value
設定為 this.state.value
,如此當 EssayForm
被 mount 起來時使用者就會看到預設 state 'Please write an essay about your favorite DOM element.'
顯示在輸入框上了。
name
同時管理多個 input當同時有多個 input 時也可以在 form element 中加入 name
prop,如此就可以 onChange
callback 就透過 event.target.name
設定對應的 state 資料,以達到同時管理多個 input 的功能:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = { text: 'initial value' };
}
changeInputValue = (e) => {
this.setState({ [e.target.name]: e.target.value });
}
render() {
return (
<div>
<input type='text' name='firstName' value={this.state.firstName} onChange={this.changeInputValue} />
<input type='text' name='lastName' value={this.state.lastName} onChange={this.changeInputValue} />
</div>
);
}
}
讀者也可以到 CodePen 上查看範例。
範例中,因為有為兩個 input
都設定 name
prop,因此當 onChange
觸發 changeInputValue
時,就可以透過 { [e.target.name]: e.target.value }
去更新使用者輸入的 input 的 state。
如果想要使用現成的解決方案來支援 React form 修改檢查(dirty)、格式驗證(validation)、追蹤拜訪欄位(visit)等功能的話,也可以考慮使用以下這些 library:
這個章節中介紹了各種 controlled form element 的語法,包括:
另外也了解了 controlled component 的使用注意事項:
Nil
時可正常輸入還有知道了 controlled component 的使用技巧: