表單是前端很是重要的一塊內容,而且每每包含了錯誤校驗等邏輯。
React對錶單元素作了專門的優化處理,他對錶單元素作了一些抽象,使得他們的使用方式更統一更規範。javascript
表單裏面出來了一個新的概念叫「約束性組件」。那麼如何理解約束性組件和非約束性組件呢。html
約束性組件,簡單的說,就是由React管理了它的value,而非約束性組件的value就是原生的DOM管理的。
他們的寫法上也有很大區別。前端
<input type="text" defaultValue="a" />
這個 defaultValue 其實就是原生DOM中的 value 屬性。這樣寫出的來的組件,其value值就是用戶輸入的內容,React徹底無論理輸入的過程。java
<input type="text" value={this.state.name} onChange={this.handleChange} />
//...省略部分代碼 handleChange: function(e) { this.setState({name: e.target.value}); }
這裏,value屬性再也不是一個寫死的值,他是 this.state.name,而 this.state.name 是由 this.handleChange 負責管理的。
這個時候實際上 input 的 value 根本不是用戶輸入的內容。而是onChange 事件觸發以後,因爲 this.setState 致使了一次從新渲染。不過React會優化這個渲染過程,實際它依然是經過設置input的value來實現的。優化
可是必定要注意,約束性組件顯示的值和用戶輸入的值雖然不少時候是相同的,但他們根本是兩碼事。約束性組件顯示的是 this.state.name 的值。你能夠在handleChange中對用戶輸入的值作任意的處理,好比你能夠作錯誤校驗。this
非約束性組件: 用戶輸入A -> input 中顯示A
約束性組件: 用戶輸入A -> 觸發onChange事件 -> handleChange 中設置 state.name = 「A」 -> 渲染input使他的value變成A
正式由於這樣,強烈推薦使用約束性組件,由於它能更好的控制組件的生命流程。spa
React 把 input,textarea 和 select 三個組件作了抽象和封裝,他們的用法變得很是統一,你基本上能夠當作同一個組件來用。code
他們如今有統一的 value 屬性 和 onChange 事件,如今對於這三種組件你均可以這樣寫orm
<input type='text' name='intro' id='intro' value={this.state.email} onChange={this.handleEmail} /> <textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} /> <textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} />
不過 chekbox有和上面三個不同,由於checkbox改變的不是 value ,而是 checked 狀態。
你能夠這樣寫:htm
<input type='radio' name='gender' checked={this.state.male} onChange={this.handleGender} value='MALE' /> <input type='radio' name='gender' checked={!this.state.male} onChange={this.handleGender} value='FEMALE' />
下面是一個包含了 input,textarea, select, radio 的表單,而且作了簡單的校驗:
var MyForm = React.createClass({ getInitialState: function() { return { email: "", intro: "", city: "hz", male: true, //性別 emailError: "", introError: "" }; }, handleEmail: function(e) { var value = e.target.value; var error = ''; if(!(/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value))) { error = '請輸入正確的Email'; } this.setState({ email: value, emailError: error }); }, handleIntro: function(e) { var value = e.target.value; var error = ""; if(value.length < 10) { error = "介紹不能少於十個字"; } this.setState({ intro: value, introError: error }); }, handleCity: function(e) { var value = e.target.value; this.setState({ city: value, }); }, handleGender: function(e) { var male = !!(e.target.value == 'MALE'); this.setState({ male: male }); }, render: function() { return ( <div> <p> <label htmlFor='email'>email:</label> <input type='text' name='intro' id='intro' value={this.state.email} onChange={this.handleEmail} /> <span>{this.state.emailError}</span> </p> <p> <label htmlFor='intro'>intro:</label> <textarea type='text' name='intro' id='intro' value={this.state.intro} onChange={this.handleIntro} /> <span>{this.state.introError}</span> </p> <p> <label htmlFor='city'>所在城市:</label> <select name='city' id='city' value={this.state.city} onChange={this.handleCity}> <option value='hz'>杭州</option> <option value='bj'>北京</option> <option value='sh'>上海</option> </select> </p> <p> <label>性別:</label> <input type='radio' name='gender' checked={this.state.male} onChange={this.handleGender} value='MALE' /> <input type='radio' name='gender' checked={!this.state.male} onChange={this.handleGender} value='FEMALE' /> </p> </div> ) } }); React.render( <MyForm />, document.getElementById("div1") );