用了 5 年 React,我不喜歡 Vue.js 的地方有這些

英文:Harry Wolff,翻譯:前端大全 / v2li

本文是我上一篇《Vue 在哪些方面比 React 做得更好?》的後續。

和上一篇不同,本文的重點不是講 Vue.js 做得比 React 好的方面,而是聊聊我不喜歡 Vue.js 的地方。

讓我們來研究一下我認爲 React 比 Vue.js 做得更好的地方吧。

引言:我儘量能客觀地來表述,但是您肯定會感受到我的一些主觀立場,畢竟,在過去 5 年中,我在專職用 React,顯然,它是我在 UI 框架中的首選。

模板
Vue.js 最大的一個特點(坦率地說,Vue.js 最大的優勢)就是其編寫 UI 的模板語法。

在使用 React 5 年之後(儘可能接近原生 JavaScript),我並不想費心去學習另一種模板語法。

在我的職業生涯中,我曾學過各種語法,比如:Mustache.js、Handlebars、Lodash、Django 甚至更多。我不想因爲要使用 Vue.js 而必須去學習另一種模板語法。

雖然每種模板語法都有一些相似之處,但它們各自的特點讓我在從一種切換到另一種的過程中非常頭痛。

另一件我不喜歡的關於模板語法的事情是,它會在你編寫的內容和在瀏覽器中運行的內容之間添加一層抽象。

React 中,會通過 JSX 編譯爲函數調用:


// React in
<div title="Hello">Message: {message}</div>;

// React out
React.createElement(div, { title: 'Hello' }, 'Message: ' + message);

而在 Vue.js 中,我不知道模板將會編譯成什麼樣。

React 和 Vue.js 在它們的模板中都僅允許使用 JavaScript 表達式,考慮到 JavaScript 的限制,我可以理解這點。但是 Vue.js 讓我感到困惑的地方是它只能訪問全局中的一部分內容。我知道這種限制肯定事出有因,但是我真的不願意在開發的時候時刻想着 Vue.js 模板不是簡單封裝了一層 JavaScript。

指令
指令是 Vue.js 的殺手級功能。它讓 Vue.js 的模板變得特別強大。

但是。

指令實際上是一種 API,您必須學習它們才能更有效地使用 Vue.js 模板。雖然與 Angular.js(我以前使用的方式)相比,Vue.js 指令少了很多,但這還是會提高你的使用成本。

而 Vue.js 賦予指令的靈活性則進一步加劇了這種情況,它帶來了更多額外的學習成本。

比如指令參數,它有動態參數 然後還有指令修飾符(雖然我在第一篇文章中把它作爲 Vue.js 的優點,但這也帶來了額外的學習成本)!

指令的大多數語法都不可怕,但是我確實發現 v-for 指令 的語法非常反 JavaScript。它比其他任何東西都更接近 Python,這出現在 JavaScript 框架中會很奇怪。

組件

這點有點吹毛求疵了,但它可以佐證我對模板的觀點。

由於 Vue.js 在很大程度上是模板驅動的框架,因此當您使用自定義組件擴展它時,您需要向 Vue.js 模板編譯器告知所使用的組件。

這導致了很多重複的代碼,在我看來似乎完全是多餘的。


// Import your components as you normally would with ES Modules
import ComponentA from './ComponentA';
import ComponentC from './ComponentC';

export default {
  components: {
    // Register them with the template compiler
    ComponentA,
    ComponentC,
  },
  // Then finally use them in your template
  template: `
        <ComponentA />
    `,
};

自定義事件
除了模板之外,自定義事件也是 Vue.js 和 React 的一個很大的區別。

React 中的所有內容都是組件和 props(到了一種很不健康的地步)。當您希望子組件與父組件進行通信時,您可以傳遞一個函數讓子組件調用:


function Parent() {
  const onClick = () => alert('hello!');
  return <Child onClick={onClick} />;
}

function Child({ onClick }) {
  return <button onClick={onClick}>Click me!</button>;
}

而在 Vue.js 中則通過事件來進行父子組件通信:


const ParentComponent = {
  components: { ChildComponent },
  template: `<ChildComponent @greeting="alert('hello')" />`,
};

const ChildComponent = {
  emits: ['greeting'],
  template: `<button @click="$emit('greeting')">Click me!</button>`,
};

老實說,我不太確定我對通過事件進行父子組件通信的看法。

由於對發出和監聽什麼事件沒有具體的約定,在 Angular.js 中使用這種方法會十分糟糕。

但是,Vue.js 通過工具解決了這個問題,當父級嘗試監聽某個事件時,組件實際上會發出這個事件。

如果不使用這個工具,我認爲 Vue.js 可能會遇到與 Angular.js 相同的問題,但是 Vue.js 的工具確實很出色。

話雖如此,React 通過 props 傳遞函數的方式也不錯,並且個人認爲它更強大。

事件處理方法
與自定義事件相關的是 Vue.js 如何爲其模板添加事件處理器。這也是我最鄙視的機制之一:引用字符串!

當在 Vue.js 模板中引用一個方法時,需要通過字符串的形式傳遞函數名稱:


<button @click="greet">Greet</button>

嗯…過去我在使用字符串引用的時候一直很糟。

但是像上面一樣,Vue.js 會通過工具捕獲任何愚蠢的錯別字。可惜,這已經是我非常不喜歡的一種方式了,並且不希望再次使用它。

響應式
Vue.js 的大部分魔力來自其響應式。它讓 Vue.js 能夠在數據改變時有效且快速地更新 UI。它使我想起了 MobX,但在 Vue.js 中它是專爲 Vue.js 設計的並且內置其中。

但是,MobX 和 Vue.js 的響應式都有權衡取捨,在組件中使用響應式時,您必須考慮其實現細節。

例如,當創建響應式對象時,您通過reactive 函數包裝對象。但是,當您想使用原始值時,需要將其包裝在 ref 中,其作用與 React 的 useRef 的 hook 非常相似。

基於 Vue.js 的響應式原理(使用 Proxy),所以當要破壞一個 reactive 對象時,則需要將其包裝在 toRefs(reactiveObject)中,以確保您不會丟失反應性綁定。

對於原始參考值,Vue.js 會自動解開模板中的參考值,這點雖然很好,但會造成引用值不一致的問題。

在模板中,您不必解包,但是在組件 JavaScript 中,您需要解包。對我而言,這些上下文切換似乎是不必要的而且乍一看會造成混亂。

對於常見的用例,確實很少會遇到這些邊緣情況,但是我很關注它的擴展性。

這與 React 幾乎都是簡單應用 useState 和 useRef 相反,後者會返回 setter 函數和一致的 ref-object 接口。也許 React 的 API 太簡單了,因此它將大多數操作推給了最終開發者。但這也是我現在最關心的,就是裏邊不要有什麼奇淫巧計。

尾聲
與 Vue.js 相比,我更喜歡 React 的哲學。

我不喜歡 Vue.js 替我做了太多事情。我更喜歡使用原始的函數和方法來完全控制我的 UI(React 就是這樣的)。

React 並非沒有怪異模式,但至少 React 的怪異點我是清楚的。我寫的東西和 React 做的事情之間幾乎沒有間接層。(忽略 react-reconciler 庫的黑暗魔力,祝那些嘗試深層次調試這些堆棧的人好運吧)。

很難說 React 更好,因爲我個人確實更偏愛 React!如果 Vue.js 更合你意,請繼續使用 Vue.js!我唯一想做的就是強調 Vue.js 和 React 之間的區別,以及爲什麼React 仍是我 UI 庫的首選。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章