說說 vue 和 react 的核心區別


Vue 和 React 的核心差異

用 Evan you 的話說:雙向綁定是對表單來說的,表單的雙向綁定,說到底不過是 value 的單向綁定 + onChange 事件偵聽的一個語法糖。

這個並不是 React 和 Vue 在理念上真正的差別體現。同時,單向數據流不是 Vue 或者 React 的差別,而是 Vue 和 React 的共同默契選擇。單向數據流核心是在於避免組件的自身(未來可復用)狀態設計,它強調把 state 拿出來進行集中管理。

而真正我認為 React 和 Vue 在理念上的差別,且對后續設計實現產生不可逆影響的是:Vue 進行數據攔截/代理,它對偵測數據的變化更敏感、更精確,也間接對一些后續實現(比如 hooks,function based API)提供了很大的便利。React 推崇函數式,它直接進行局部重新刷新(或者重新渲染),這樣更粗暴,但是更簡單,就是刷新唄,前端開發非常簡單。但是 React 並不知道什么時候“應該去刷新”,觸發局部重新變化是由開發者手動調用 setState 完成。

React setState 引起局部重新刷新。為了達到更好的性能,React 暴漏給開發者 shouldComponentUpdate 這個生命周期 hook,來避免不需要的重新渲染(相比之下,Vue 由於采用依賴追蹤,默認就是優化狀態。而 React 對數據變化毫無感知,它就提供 React.createElement 調用已生成 virtual dom)。

另外 React 為了彌補不必要的更新,會對 setState 的行為進行合並操作。因此 setState 有時候會是異步更新,但並不是總是“異步”。

以及核心差異對后續設計產生的“不可逆”影響

在設計上,react 給開發者帶來了額外的“心智負擔”,也引出了一些潛在問題。Vue 的響應式理念,進行數據攔截和代理中不存在類似問題。

這個設計上的差別,直接影響了 hooks 的實現和表現。

setup hook 介紹

setup hook 是 vue3 推出的新功能,對標 react 的 setup hook。

對比 Class API(vue3 已經廢除了它):

  • 他能更好的支持ts的 類型推導支持(因為ts對函數的入參出參的推導支持力度大,而對class和對象的屬性推導的支持度小,不需要寫額外的類型聲明)。
  • 更靈活的邏輯復用能力。這是因為其他的邏輯注入如 vue mixins 存在多個時容易造成命名沖突,模版里使用的數據來源不清晰等問題,而高階組件同樣有 props 命名沖突和來源不清的問題,但是 setup hook 沒有。因為 setup 本身返回一個對象,是可以在調用的 vue 實例里解構的,它沒有命名沖突和數據來源不清的情況
  • tree-shaking 友好(setup函數里的computed,watch等方法若不用到,那么最后打包產生的代碼會去掉)
  • 代碼更容易被壓縮(因為函數內的變量名可以被隨意壓縮混淆成單個字母,而對象或者類的屬性壓縮起來不安全,就不會壓縮 )

對比 React hook:

React hook 底層是基於鏈表(Array)實現,每次組件被 render 的時候都會順序執行所有的 hooks,因為底層是鏈表,每一個 hook 的 next 是指向下一個 hook 的,所以要求開發者不能在不同 hooks 調用中使用判斷條件,因為 if 會導致順序不正確,從而導致報錯。

相反,Vue 3 hook 只會被注冊調用一次,Vue之所以能避開這些麻煩的問題,根本原因在於它對數據的響應是基於響應式的,是對數據進行了代理的。不需要鏈表進行 hooks 記錄,它對數據直接代理觀察。

但是 Vue 這種響應式的方案,也有自己的困擾。比如 useState() (實際上 evan 命名為 value())返回的是一個 value wrapper (包裝對象)。一個包裝對象只有一個屬性:.value ,該屬性指向內部被包裝的值。我們知道在 JavaScript 中,原始值類型如 string 和 number 是只有值,沒有引用的。不管是使用 Object.defineProperty 還是 Proxy,我們無法追蹤原始變量后續的變化。因此 Vue 不得不返回一個包裝對象,不然對於基本類型,它無法做到數據的代理和攔截。這算是因為設計理念帶來的一個非常非常微小的 side effect。從 Evan you 的截圖中,我圈了出來:

Vue 和 React 在 API 設計風格的不同

React 事件系統龐大而復雜。它暴漏給開發者的事件不是原生事件,並且 this 不是指向組件或者實例本身。

React 的事件是包裝過的合成事件,並且非常重要的一點是,不同的事件可能會共享一個合成事件對象。另外一個細節是,React 對所有事件都進行了代理,將所有事件都綁定 document 上。請讀者仔細體會下面的代碼:

class clickTest extends React.Component {
  componentDidMount() {
    document.addEventListener('click', () => {
      console.log('document click');
    });
  }
  
  handleClick(evt) {
    console.log('div click', evt);
    console.log(this);
    evt.stopPropagation();
    // 觸發點擊后會打印
    // div click
    // document click
    
    // 並且 this 是 undefined。
  }
  
  render() {
    return (
      <div onClick={this.handleClick}> click </div>
    )
  }
}

上文代碼觸發點擊事件后,兩個 console.log 都打印是因為壓根沒能有效的阻止事件冒泡,因為React 對所有事件都進行了代理,將所有事件都綁定 document 上。

然而改成下文的代碼就可以只打印 div click

handleClick(evt) {
  console.log('div click');
  console.log(evt, evt.nativeEvent);
  // 如果有多個相同類型事件的事件監聽函數綁定到同一個元素,
  // 當該類型的事件觸發時,它們會按照被添加的順序執行。
  // 如果其中某個監聽函數執行了 event.stopImmediatePropagation() 方法,
  // 則當前元素剩下的監聽函數將不會被執行。
  //(譯者注:注意區別 event.stopPropagation )
  evt.nativeEvent.stopImmediatePropagation();
}

其實想解決 react 函數 this 指向的問題,最穩妥的也只能是開發者 bind 手動綁定一下作用域了,這個做法同樣是增加了開發者的心智負擔。

Vue 事件系統

Vue 事件處理函數中的 this 默認指向組件實例。綁定的過程源碼也清晰的給出

function nativeBind (fn, ctx) {
  return fn.bind(ctx)
}

var bind = Function.prototype.bind
  ? nativeBind
  : polyfillBind;

渲染的比對

jsx 和手寫的 render function 是是完全動態的,過度的靈活性導致運行時可以用於優化的信息不足,所以 react 就只能顯示調用 setState 來強行更新組件。由於無從減掉一些不必要的渲染對比,所以 react 對此的解決方法就是引入了時間分片 react fibber,把 patch 並且更新視圖的過程切分成多個任務,分批更新。

這點是 vue3 曾經考慮過做時間分片,由於 Evan you 覺得只要更有效率的 diff,16.67 ms 的更新時間已經足夠,不需要分片。因為 vue 會標明某些 dom 是靜態的,並且 Vue 3.0 提出的動靜結合的 DOM diff 思想,開始做到了標記哪個 DOM 綁定了變量需要 patch,省去也不必要的 patch 更新的優化操作。

之所以能夠做到 Vue 3.0 預編譯優化,是因為 Vue core 可以靜態分析 template,在解析模版時,整個 parse 的過程是利用正則表達式順序解析模板,當解析到開始標簽、閉合標簽、文本的時候都會分別執行對應的回調函數,來達到構造 AST 樹的目的。

這點是 React 達不成的,它只能重新渲染更新,React 拿到的或者說掌管的,所負責的就是一堆遞歸 React.createElement 的執行調用,它無法從模版層面進行靜態分析。因此 React JSX 過度的靈活性導致運行時可以用於優化的信息不足。

當然 React 並不是沒有意識到這個問題,他們在積極的同 prepack 合作。力求彌補構建優化的先天不足。

Prepack 同樣是 FaceBook 團隊的作品。它讓你編寫普通的 JavaScript 代碼,它在構建階段就試圖了解代碼將做什么,然后生成等價的代碼,減少了運行時的計算量,就相當於 JavaScript 的部分求值器。

參考

Vue.js作者尤雨溪在 VueConf 談 Vue 3.0-騰訊視頻

前端:Vue和React的優點分別是什么?兩者的最核心差異對比是什么?

vuejs-對比其他框架


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM