英文:Harry Wolff,翻譯:前端大全 / v2li前端
本文是我上一篇《Vue 在哪些方面比 React 作得更好?》的後續。react
和上一篇不一樣,本文的重點不是講 Vue.js 作得比 React 好的方面,而是聊聊我不喜歡 Vue.js 的地方。瀏覽器
讓咱們來研究一下我認爲 React 比 Vue.js 作得更好的地方吧。框架
引言:我儘可能能客觀地來表述,可是您確定會感覺到個人一些主觀立場,畢竟,在過去 5 年中,我在專職用 React,顯然,它是我在 UI 框架中的首選。ide
模板
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 庫的首選。