Vue 中大家非常熟悉的一個API就是 setState。它是作為Vue實例的一個屬性存在,在我們通過JS代碼修改數據時,常常會使用到 setState()。那么Vue中的setState又是怎樣實現的呢?
首先,我們知道Vue中的響應式數據是通過Object.defineProperty()方法來實現的。只要我們給一個對象綁定上這個方法實現getter和setter函數,當屬性被訪問時就會執行getter函數,當屬性被賦值時執行setter函數。這樣就能夠監聽對象中屬性的變化,從而及時響應變化。在數據發生變化時,Vue將會重新渲染虛擬DOM,最終更新頁面中的數據。
let obj = {text: 'hello world'}; Object.defineProperty(obj, 'text', { get() { console.log('Getter has been called'); return this._text; }, set(newValue) { console.log('Setter has been called'); this._text = newValue; } })
在Vue中,數據響應式原理和上述類似。我們在Vue組件中使用的數據,也就是data數據,也是通過Object.defineProperty()來實現。當我們通過 this.xxx 修改數據時,觸發setter函數,會將對應的Vue實例中的數據進行修改,并且觸發對應的組件重新渲染。
let vm = new Vue({ data: { count: 0 } }) vm.count = 1;
那么Vue中的setState和上述有什么不同呢?事實上Vue中的setState是對數據進行了深拷貝,然后才進行了修改。
在Vue中,雖然我們可以通過直接修改 data 數據來更新頁面,但更新數據的正確姿勢應該使用 setState() 方法,以便確保我們的代碼能夠運行在不同的環境和框架中。而Vue中setState的具體實現原理如下:
Vue.prototype.setState = function(newState) { const oldState = this._data; this._data = merge(oldState, newState); // 深拷貝 this.$options.watch.call(this, newState, oldState); // 執行 watch this.$options.lifecycle.beforeUpdate.call(this); // 執行 beforeUpdate 生命周期 this.__update(); // 觸發數據更新 this.$options.lifecycle.updated.call(this); // 執行 updated 生命周期 }
從上述代碼中我們可以看到,setState其實是將當前數據進行了深拷貝。拷貝完成之后,觸發watch函數來監聽數據變化。當監聽到數據變化后,就會執行beforeUpdate和updated兩個生命周期函數,同時重新渲染視圖。
總的來說,Vue中的setState原理是通過深拷貝數據,觸發watch監聽數據變化,重新渲染視圖完成的。在編寫Vue代碼時盡量使用setState方法來修改和更新數據,確保代碼在不同的環境中能夠正常運行。