state
和 setState
控制資料的組件。ref
取得 DOM
元素中的資料做操控的組件。ref
會讓組件不好長期維護,所以應該盡量使用受控組件。state
做管理不是很方便,因此通常在開發時候都會搭配第三方套件,在官方文件中推薦使用的套件是 Formik,它提供很多處理表單用的組件,裡面包裝了很多驗證用的函式。受控組件是透過 setState
來控制表單資料的輸入變化,因此 state
就是唯一的數據來源。下面是一個登入頁面的受控組件,裡面的表單就是透過 setTate
來監聽資料的改變,而去更新 state
,在資料取得後,只要點擊登入按鈕,就能在 signIn()
函式中取得最新的 state
並進行登入流程的驗證。
class SignInPage extends React.Component {
state = {
userName: '',
password: ''
}
signIn () {
//取得用戶登入資料
const { userName, password} = this.state
console.log('userName', userName, 'password', password)
// 處理登入驗證流程 ...
}
render () {
const { userName, password} = this.state
return <div>
<form>
<div>
<label>User Name:</label>
<input
type="text"
value={ userName }
onChange={ e => this.setState({ userName: e.target.value })}
/>
</div>
<div>
<label>Password:</label>
<input
type="text"
value={ password }
onChange={ e => this.setState({ password: e.target.value })}
/>
</div>
</form>
<button onClick={ this.signIn.bind(this) }>Sign in</button>
</div>
}
}
前面有提到,非受控組件是透過 ref
來取得資料,而不是 state
,所以它的資料其實是從 DOM
取得,這讓它相對更容易和第三方套件做搭配。下面的範例中,我們像之前提過的利用 createRef()
建立 ref
並配置在標籤中以取得 input
的值,之後便能執行登入驗證。不過這種一般表單的處理,React 官方不建議使用 ref
處理,這邊僅僅是做一個範例而已。
class SignInPage extends React.Component {
userNameRef = React.createRef()
passwordRef = React.createRef()
signIn () {
//取得用戶登入資料
const userName = this.userNameRef.current.value
const password = this.passwordRef.current.value
console.log('userName', userName, 'password', password)
// 處理登入驗證流程 ...
}
render () {
return <div>
<form>
<div>
<label>User Name:</label>
<input
type="text"
ref={this.userNameRef}
/>
</div>
<div>
<label>Password:</label>
<input
type="text"
ref={this.passwordRef}
/>
</div>
</form>
<button onClick={ this.signIn.bind(this) }>Sign in</button>
</div>
}
}
課程中提到比較典型的非受控組件使用,一般是處理文件上傳。下面的範例中,我們一樣是透過 ref
取得 DOM
元素的值來做上傳處理,但比較不同的是,我們從 current
屬性中取得的不是 value
,而是取得 files
。files
是一個陣列,裡面會包含所有要上傳的檔案,這是和 value
比較不同之處。
class UploadFile extends React.Component {
fileRef = React.createRef()
uploadFile () {
const file = this.fileRef.current.files
// 取得上船的文件
console.log(file)
}
render () {
return <div>
<form>
<div>
<label>File:</label>
<input type="file" ref={ this.fileRef } />
</div>
</form>
<button onClick={ this.uploadFile.bind(this) }>Upload</button>
</div>
}
}
這一篇整理了受控組件和非受控組建的基本運用方式,不過在實際開發中,表單驗證還是經常會使用第三方套件來做處理,能夠省卻不少開發上的流程和時間。