?
本文檔使用 php中文網(wǎng)手冊 發(fā)布
HTML表單元素與React中的其他DOM元素有點不同,因為表單元素自然會保留一些內(nèi)部狀態(tài)。例如,這個純HTML格式的表單接受一個名稱:
<form> <label> Name: <input type="text" name="name" /> </label> <input type="submit" value="Submit" /> </form>
此表單具有用戶提交表單時瀏覽到新頁面的默認HTML表單行為。如果你想在React中使用這種行為,那就行了。但是在大多數(shù)情況下,使用JavaScript函數(shù)可以方便地處理提交表單并可以訪問用戶在表單中輸入的數(shù)據(jù)。實現(xiàn)這一目標的標準方法是使用稱為“受控組件”的技術(shù)。
在HTML中,表單元素(例如<input>
,<textarea>
)<select>
通常保持其自己的狀態(tài)并根據(jù)用戶輸入進行更新。在React中,可變狀態(tài)通常保存在組件的狀態(tài)屬性中,并且只能使用更新setState()
。
我們可以通過使React狀態(tài)成為“單一真相源”來結(jié)合這兩者。然后,呈現(xiàn)表單的React組件也控制后續(xù)用戶輸入中以該表單發(fā)生的事情。輸入表單元素的值由React以這種方式控制,稱為“受控組件”。
例如,如果我們想讓前面的示例在提交時記錄名稱,我們可以將表單編寫為受控組件:
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> ); } }
由于value
屬性設(shè)置在我們的表單元素上,因此顯示的值將始終為this.state.value
,使React狀態(tài)成為真值的來源。由于handleChange
每次擊鍵時都會運行以更新React狀態(tài),因此顯示的值將隨用戶鍵入而更新。
對于受控組件,每個狀態(tài)變異都會有一個關(guān)聯(lián)的處理函數(shù)。這使修改或驗證用戶輸入變得非常簡單。例如,如果我們想強制使用全部大寫字母來編寫名稱,我們可以這樣寫handleChange
:
handleChange(event) { this.setState({value: event.target.value.toUpperCase()});}
在HTML中,一個<textarea>
元素通過子元素定義其文本:
<textarea> Hello there, this is some text in a text area</textarea>
在React中, 改為<textarea>
使用value
屬性。這樣,使用a的表單<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>Name:<textarea value={this.state.value} onChange={this.handleChange} /></label> <input type="submit" value="Submit" /> </form> ); } }
注意this.state.value
在構(gòu)造函數(shù)中初始化,以便文本區(qū)域以其中的一些文本開始。
在HTML中,<select>
創(chuàng)建一個下拉列表。例如,這個HTML創(chuàng)建一個下拉列表:
<select> <option value="grapefruit">Grapefruit</option> <option value="lime">Lime</option> <option selected value="coconut">Coconut</option> <option value="mango">Mango</option> </select>
請注意,由于selected
屬性,Coconut選項最初被選中。反應(yīng),而不是使用此selected
屬性,使用value
根select
標簽上的屬性。這在受控組件中更方便,因為您只需要在一個位置更新它。例如:
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 La Croix 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> ); } }
總的來說,這使得它,這樣<input type="text">
,<textarea>
和<select>
所有的工作非常相似-他們都接受value
,你可以用它來實現(xiàn)控制組件屬性。
注意您可以將數(shù)組傳遞給該
value
屬性,從而允許您在select
標簽中選擇多個選項:<select multiple = {true} value = {'B','C'}>
當(dāng)需要處理多個受控input
元素時,可以name
為每個元素添加一個屬性,并讓處理函數(shù)根據(jù)值來選擇要執(zhí)行的操作event.target.name
。
例如:
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> ); } }
請注意,我們?nèi)绾问褂肊S6 計算的屬性名稱語法來更新與給定輸入名稱對應(yīng)的狀態(tài)鍵:
this.setState({ [name]: value});
它相當(dāng)于這個ES5代碼:
var partialState = {};partialState[name] = value;this.setState(partialState);
此外,由于setState()
自動將局部狀態(tài)合并到當(dāng)前狀態(tài),因此我們只需要用改變的部分調(diào)用它。
在受控組件上指定值prop可以防止用戶更改輸入,除非您愿意。如果您已指定a value
但輸入仍可編輯,則可能意外設(shè)置value
為undefined
或null
。
以下代碼演示了這一點。(輸入首先被鎖定,但在短暫延遲后變?yōu)榭删庉?。?/p>
ReactDOM.render(<input value="hi" />, mountNode); setTimeout(function() { ReactDOM.render(<input value={null} />, mountNode);}, 1000);
使用受控組件有時會非常乏味,因為您需要為數(shù)據(jù)可以改變的每種方式編寫一個事件處理程序,并通過React組件管理所有輸入狀態(tài)。當(dāng)您將預(yù)先存在的代碼庫轉(zhuǎn)換為React或?qū)eact應(yīng)用程序與非React庫集成時,這會變得特別煩人。在這些情況下,您可能需要檢查不受控制的組件,這是實現(xiàn)輸入表單的另一種技術(shù)。