Vue 與 React 有什麼區別?
這是前端開發同學面試時經常遇到的問題。
我最開始接觸的是 React,對 Vue 的理解一直比較片面,感覺 Vue 要學很多 html 指令,很不習慣,也沒覺得 Vue 比 React 有什麼優勢。
直到現在,使用了 Vue 一年之後,對 Vue 有了更多感受,也消除了一些刻板印象。
首先,這兩個框架都是非常優秀的,它們其實非常相似,都有以下特性:
- 響應式(Reactive)。兩個框架都是一種類似 VM 的架構,將狀態從視圖層分離出來,開發者只需要關注業務邏輯,不需要直接操作 DOM 。當應用發生改變時,我們只需要更新狀態即可,框架會自動幫我們重新渲染頁面。
- 組件化(Composable)。一個頁面,可以拆分成一棵嵌套的組件樹,我們只需要開發一個個組件即可,同一個組件可以在多個地方使用,這樣就提升了代碼的複用性和可維護性。
- Virtual DOM。框架在操作真實 DOM 之前,會先在內存中生成虛擬 DOM,最後再批量操作真實 DOM,以提高性能。
至於它們的區別,我個人理解,最大的有以下三點:
- 響應式原理不同;
- Vue 推薦使用模版的方式定義組件,React 推薦使用 JSX;
- React 推薦使用不可變的數據;
當然它們肯定還有其他區別,比如代碼實現、狀態管理等,但上面這三點是它們比較大的區別,是框架有意為之的,對日常的開發和理解影響也是比較大的。
一、響應式原理不同
Vue 使用觀察者模式自動跟蹤數據的變化,自動更新組件。
Vue 會遍歷 data 數據對象,使用 Object.defineProperty() 將每個屬性都轉換為 getter/setter。每個 Vue 組件實例都有一個對應的 watcher 實例,在組件初次渲染(render)時,會記錄組件用到了(調用 getter)哪些數據。當數據發生改變時,會觸發 setter 方法,並通知所有依賴這個數據的 watcher 實例,然後 watcher 實例調用對應組件的 render 方法,生成一顆新的 vdom 樹,Vue 會將新生成的 vdom 樹與上一次生成的 vdom 樹進行比較(diff),來決定具體要更新哪些 dom。
React 必須顯式調用 setState() 方法更新狀態,狀態更新之後,組件也會重新渲染。
Vue 和 React 在狀態更新之後,都會生成一顆新的虛擬 dom 樹,與上一顆虛擬 dom 樹進行比較(diff),找出其中的差異,再更新真實 dom。這個虛擬 dom diff 算法,Vue 與 React 差異其實並不大,基本思想是差不多的。大家可以看看網上的文章,我這裏就不展開了。
二、Vue 推薦使用 template 定義組件,React 推薦使用 JSX
Vue 推薦使用 template 的方式定義組件,因為這樣更接近原生 html,可以在不破壞原有 html 代碼的基礎上引入 Vue 的能力。Vue 的組件也參考了一些 Web Component 的規範,Vue 的組件可以很容易打包成 Web Component。
React 推薦使用 JSX,JSX 是使用 JS 的語法來編寫 html 代碼,所以一些流程控制,數據綁定也會更加方便。也不需要再學一套模板語法。
事實上 Vue 也提供了 JSX 的支持,不過 Vue 更推薦 template 的方式。
三、React 推薦使用不可變的數據
這一點對於從 Vue 轉換到 React 的同學,需要特別注意。
所謂不可變的數據,就是當我們要改變一個數據對象時,不要直接修改原數據對象,而是返回一個新的數據對象。比如使用 Object.assign() 方法修改數據屬性:
const data = {
fontSize: 14,
color: "black"
};
const newData = Object.assign({}, data, { color: "blue" });
之所以推薦使用不可變的數據,一個原因是使用不可變的數據,可以更容易的實現“時間旅行”功能。但是更重要的一個原因是可以更容易的實現 pure component。
當一個組件的狀態發生改變時,React 會重新調用 render() 方法,比較生成的 VDOM 的差別。如果一個子組件的 proos 和 state 都沒有改變,React 仍然需要進行一次對比,這個情況就有點兒浪費了。所以 React 提供了 shouldComponentUpdate() 生命週期函數,允許開發者判斷什麼時候應該更新組件,比如當組件的 props 和 state 都沒有改變的時候,shouldComponentUpdate 就可以返回 false,那麼 React 就不會再去比較 VDOM 的差異了。
React.PureComponent 類,實現了 shouldComponentUpdate 方法,會對 props 和 state 進行淺比較,如果沒有變化,就返回 false 跳過組件更新。但是它只進行淺比較,所以如果直接修改了 props 或 state 的屬性,shouldComponentUpdate 方法還是返回 false,就漏掉了這次更新。所以這種情況下,推薦使用不可變的數據。
更多信息請看官方文檔:為什麼不可變性在 React 中非常重要