iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
0
自我挑戰組

React 30 天學習歷程系列 第 19

【Day 19】 受控組件(Controlled Component)與非受控組件(Uncontrolled Component)

  • 分享至 

  • xImage
  •  
  • 受控組件(Controlled Component)指的是受 statesetState 控制資料的組件。
  • 非受控組件(Uncontrolled Component)指的是利用 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,而是取得 filesfiles 是一個陣列,裡面會包含所有要上傳的檔案,這是和 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>
    }
}

小結

這一篇整理了受控組件和非受控組建的基本運用方式,不過在實際開發中,表單驗證還是經常會使用第三方套件來做處理,能夠省卻不少開發上的流程和時間。


上一篇
# 【Day 18】 ref 使用
下一篇
【Day 20】React Portals 和 PropTypes 檢查
系列文
React 30 天學習歷程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言