這兩個月實習期時間踩了不少坑,先來談談有代表性的一個。
我們知道表單是前端里很常見的一個東西,往往包含了很多數據校驗邏輯。
React、antd 對表單元素專門做了優化處理,有了一些抽象的東西,使得他們的使用方式更統一更規范。。
在一次需求開發中,有一塊是這樣的:首先渲染一個Table,里面每一項都有個“編輯”操作,點擊彈出Modal框
如圖所示:
這個Modal框是一個表單,里面的文本框 下拉框等 都帶有從Table里對應的那一項傳來的默認值
於是我習慣性地想到了設置 “defaultValue”,如下圖。。
但跑起來后發現這樣一個問題:
第一次點開彈出框,他帶的默認值是正確的:
但當我在Table里改變了此項數據再次點開,它並沒有按照設想的顯示改變后的選項,而是一直固定在“是”。
解決這個問題前,先來回顧一下React的 受控和非受控組件
“在 HTML 中,表單元素(如<input>
、 <textarea>
和 <select>
)之類的表單元素通常自己維護 state,並根據用戶輸入進行更新。而在 React 中,可變狀態(mutable state)通常保存在組件的 state 屬性中,並且只能通過使用 setState()
來更新。我們可以把兩者結合起來,使 React 的 state 成為“唯一數據源”。渲染表單的 React 組件還控制着用戶輸入過程中表單發生的操作。被 React 以這種方式控制取值的表單輸入元素就叫做“受控組件”。” ——React docs
這里有一個新的概念叫“受控組件”。那么如何理解受控組件和非受控組件呢。
受控組件,簡單的說,就是由React管理了它的value,而非受控組件的value就是原生的DOM管理的。
他們的寫法上也有很大區別。
例如,非受控組件這么寫:
<input type="text" defaultValue="a" />
這個 defaultValue 其實就是原生DOM中的 value 屬性。
這樣寫出的來的組件,其value值就是用戶輸入的內容,React完全不管、也管不到輸入的過程。
而受控組件是這么寫的:
<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中對用戶輸入的值做任意的處理,比如數據校驗。
對比受控組件和非受控組件的輸入流程:
- 非受控組件: 用戶輸入A => input 中顯示A
- 受控組件: 用戶輸入A => 觸發onChange事件 => handleChange 中設置 state.name = “A” => 渲染input使他的value變成A
正式因為這樣,使得 React 的 state 成為唯一數據源。對於受控組件來說,輸入的值始終由 React 的 state 驅動。
所以官方強烈推薦使用受控組件,因為它能更好的控制組件的生命流程。
所以回到我代碼中的問題,解決辦法就是:
將defaultValue 改成 value={this.state.XXX},然后在外邊寫一個 handleXXX 函數,通過 setState 來控制value的值。
使之成為一個受控組件,這樣就沒問題了