天天看點

受控元件分析(React & Vue)

受控元件:元件的值的更新依賴狀态值來更新,一定程度上,元件值是恒等于狀态值的。

非受控元件:元件值更新由元件自己維護,需要以操作 DOM 的方式來擷取元件的值。

在 React 中表現如下:

input 中設定了 value,則為受控元件,onChange 事件設定如下:

不設定 onChange 事件,輸入内容,input 并不會渲染出來。因為 input 值的更新,是依賴狀态值來更新的(渲染),是以 input 不會渲染輸入的内容。

設定 onChange 事件,但 onChange 事件中不更新狀态值/設定狀态值為某個值,并不是使用者輸入的值的時候,input 也不會正确地渲染。理由同上。

設定 onChange 事件,且設定狀态值為輸入值(e.target.value)時,input 将正确渲染内容。

如不設定 value,則 input 元件屬于非受控元件。使用者輸入的内容,将由 input 元件維護(更新渲染行為不受到程式控制)。

在 Vue 中,有兩種常用的設定方式,一種怪異的設定方式,不同設定,表現不同。

表現正常,效果如 React 的設定 value 和正确設定 onChange 事件的情況一緻。

input 的表現(渲染)跟值分離了。this.value 還是設定為 123 ,但 input 卻正确地響應了使用者的輸入。

這種情況,日常開發是不會這樣發生的。這裡的 input 表現是符合邏輯的。如設定 this.value=123 則 input 的渲染不會渲染使用者輸入的内容,而是 123。如不設定 this.value 的值,則 input 表現跟 v-model 的情況一緻。

首先,不會去分析 v-model & @input 這種怪異的用法的。

v-model 的表現表明元件是可控的。是以分析一下 :value & @input 表現跟狀态不一的情況。

為什麼這種情況下,表現和狀态不一呢?

我們知道 Vue 是采取依賴收集的這種方式去發現更新情況,然後更新視圖的。當 input 輸入時,會觸發 @input 事件,但 @input 事件中,對 value 的處理是賦一個常數值(this.value = 123)。此時,this.value 值相同,并沒有觸發更新,是以 Vue 認為 input 元件不需要跟新,也就不會去更新視圖,是以 input 會響應使用者的輸入,但卻沒有觸發 Vue 更新。

如何證明以上結論是正确的呢?請看下面 2 種情況:

如将 this.value = 456  ,那麼 input 會先從 123 變成 456,而後表現跟上面分析一緻。因為 @input 中 this.value 指派是常數,不會觸發 Vue 更新視圖,而 input 則是響應了使用者的輸入。

如将 this.value = Math.random() ,input 的内容會随着使用者輸入而變化(并不是使用者輸入的值),因為 this.value 得到了更新,是以 Vue 更新了視圖,将 input 的内容同步為 this.value 的值。

從上文可知,React 跟 Vue 的差別在于:React 強制性使 input 的更新跟狀态值的更新同步;而 Vue 則隻會在狀态值更新的時候才會同步更新視圖,如狀态值不變(如設定常亮this.value = 123),元件的視圖更新将表現為非受控。

是因為它們的更新方式是不一樣的。

Vue:依賴收集,資料更新後更新視圖。

React:依靠 Render 和 Diff 配合更新,每次更新都會将狀态值和視圖同步。

是以,input 元件,綁定的狀态值是 this.value ,onChange/@input 事件的處理是設定狀态值等于一個常量:setValue(123) / this.value = 123,那麼當使用者在 input 輸入内容時:

Vue:咦,狀态沒更新,不用更新視圖,美滋滋!

React:嗯?狀态是這個,視圖渲染了那個,鬧啥呢,同步一下!于是将視圖上的值改為狀态值。

受控元件的關鍵點在于,狀态值更新會同步視圖更新,一定條件下元件的值恒等于狀态值;

React 的受控元件,狀态值跟視圖是兩兩強綁定關系的,元件值恒等于狀态值;

Vue 的受控元件,狀态值更新一定會同步視圖更新,此時元件值恒等于狀态值;但視圖更新在特殊情況下(如視圖更新了,但狀态值保持不變),元件值不等于狀态值;

React 和 Vue 的受控元件表現略微差異的原因在于它們不同的更新方式,Vue 着重于狀态值的更新情況來更新視圖,而 React 會強制狀态值和視圖保持同步。