在大多數狀況下,咱們推薦使用 受控組件 來處理表單數據。在一個受控組件中,表單數據是由 React 組件來管理的。另外一種替代方案是使用非受控組件,這時表單數據將交由 DOM 節點來處理。
以上是 React 官網對受控組件與非受控組件的一次解釋,大學剛剛畢業時候,看到這一段, 實在有些難以接受,在我看來,既然已經選擇使用了 React ,就應該徹底完全的使用受控組件,爲何開發者會有直接使用 DOM 節點開發的的非受控組件。當時在 vue 中,並無這種設定。同時我當時在開發 Sass 網站,由於在開發 pc 端網站老是須要即時驗證(即時給予用戶交互,不讓用戶在填寫完整的數據後再提示錯誤以至於過度沮喪)。html
不過如今來看,非受控組件的確是 React 很是好的設計。前端
非受控的輸入就像傳統的HTML表單輸入同樣:vue
class Form extends Component { /** 提交時候獲取數據 */ handleSubmitClick = () => { const name = this._name.value; // 檢測數據提示而後 } render() { return ( <div> <input type="text" ref={input => this._name = input} /> <button onClick={this.handleSubmitClick}>Sign up</button> </div> ); } }
咱們只有在觸發其餘事件(例如點擊提交按鈕時),才能夠獲取 DOM 數據中的值。react
受控的輸入接受當前的值做爲參數,而且在值發生改變的時候執行回調函數。git
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('提交的名字: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> 名字: <input type="text" value={this.state.value} onChange={this.handleChange} /> </label> <input type="submit" value="提交" /> </form> ); } }
當用戶一旦進行了數據的修改,程序馬上就能夠知道哪些狀態發生了改變,這時候咱們就能夠基於狀態修改來構建更好的表單交互與用戶體驗。github
受控與非受控組件能夠類比服務器和客戶端的 push 和 pull 模型,push 是服務器主動發送數據給客戶端,一旦有「數據改變」就當即推送,因此用戶能夠基於最新的消息作處理,而 pull 模型無法知道數據的細節變化,即便遇到了錯誤輸出也只能間接檢查通知用戶。gulp
若是你的表單在交互的過程當中足夠簡單,僅僅只須要提交時候驗證,而且沒有級聯數據,強制格式輸入等複雜用戶交互。那麼能夠選擇非受控組件。固然選擇並非一次性的,咱們能夠在開發過程當中遷移非受控組件到受控組件(應該沒有小夥伴反向操做吧)。小程序
事實上,咱們在生活與開發過程當中,老是會遇到相似 React 中受控與非受控組件等同的問題。其實也就是全量與增量問題。基於不一樣的領域,不一樣的設計目標,不一樣的用戶,不一樣的團隊,當前受限的資源以及當下要完成的目標設定,都會影響問題的最終決策。這裏我列出最近我遇到的幾個問題。供你們參考閱讀。api
從去年開始,新項目都使用 TypeScript 進行開發,面對複雜的大型項目來講,TypeScript 利好不言而喻。尤爲在業務不穩定,面臨大量改動時候。動態類型總會讓人擔驚受怕。對於老項目,咱們也想從中獲得 TypeScript 的利好。安全
前端的 Vue 項目已經開發 3 年多了,當前的項目也從一個簡單的單頁面應用程序變成了基於業務的多頁面應用。同時也拆分出來一系列的基礎庫與 widget。
咱們都知道修改必然是從基礎升級,目前咱們還面臨着繁重的開發任務,因此咱們沒有時間資源進行全量升級,同時基礎依賴中也有 Vue 業務組件。Vue 3 此時的開發進度也讓咱們「進退兩難」。因此咱們只能想去改動非組件的輔助代碼。
這是咱們先增長了 tsc 編譯配置,可讓新模塊使用 TypeScript,同時能夠在空閒時候修改部分老代碼。
可是,做爲依賴庫,僅僅只在內部 TypeScript 代碼是不夠的,進一步來講,老大還想要定義文件(.d.ts)輔助其餘項目開發。因此咱們使用 tsc 編譯出當前代碼的全部 TypeScript 定義文件,而後使用 gulp-insert 對定義文件進行修改後投入使用。
面對移動端 Sass 開發,咱們仍要提供複雜的表單,同時移動端不須要太多的交互。結合小程序 setData 很是耗費性能,同時小程序組件不像 Vue,React 有單向數據流的說法。因此數據放在各個組件內部反而更好,最後在提交時候,把各個組件的數據組合起來進行驗證與對比提交,不管是性能仍是開發都具備更好的體驗。因此小程序表單提交反而使用「非受控組件」更好。
固然,移動端表單的側重點是減小用戶的輸入,開發的精力應該投入在表單的默認數據上,從而減小用戶的輸入操做。
在用戶創造價值的時代中,審覈用戶提供的數據必定是重中之重。而咱們目前小程序能夠提供分享功能。而小程序自己也有查詢文本安全的增值服務 api security.msgSecCheck。
這時候咱們有兩種選擇,咱們能夠每一次提交可分享數據時候檢查並提示含有非法字符,這樣用戶能夠清楚的知道該次的數據提交中有非法字符。固然也能夠在最終分享的時候提示有非法信息,可是此時面對如此大的數據量分享,用戶恐怕很難查詢出到底是哪條信息出了問題。到底是那種方式更好?這取決於小程序的用戶量以及投入的資源。
同時還有不少例子,例如 js 文件修改,到底是增量(字符串級別)仍是全量(單個 js 文件) ? 你們須要根據公司和項目來判斷。因此究竟使用什麼方式,取決於你的業務,所擁有的資源,甚至是你面對的客戶量級。
若是你以爲這篇文章不錯,但願能夠給與我一些鼓勵,在個人 github 博客下幫忙 star 一下。
博客地址