为什么我们放弃了Vue?Vue和React深度比较
我使用Vue和React已經很長一段時間了,兩個框架上實踐代碼量都在10萬行以上。不得不說都是都很不錯的,幫助開發者減少很多工作量,某種框架是現代化Vue和React在兩者之間的選擇并不像選擇蘋果或香蕉一樣簡單,兩者在工程實踐上的差異讓我們逐漸放棄了Vue。此處以不一樣的角度對彼此進行深度對比。
常見搖擺問題,觀點
首先,我重新談談常見對比項目,觀點的看法,這些部分內容可以通過一些文章或者Vue官方對比文檔查到,主要目的是幫助小白解決入門搖擺問題。如果你反對,歡迎評論區留言Battle,反正我不會回答你這類問題。
Vue或React文檔更豐富?
兩者都有豐富的文檔(包括中文文檔),Vue文檔,React中文,所以不用擔心你四級都過不了,看不懂文檔,這都是有眼就行的事?當然,如果你提前懂點javascript相關知識也是大大滴好,ES6語法更佳,可以在這里跟阮老師學習,免費的電子書。文檔和持續進階不是你在兩個框架間做選擇的原因。
Vue的話需要記住各種指令,還有屬性細節,免不了經常查文檔。React相對簡單,記住:“函數入口是props,出口是html”就行了。
React學習門檻高?
這個也不是你選擇框架的原因,如果這個也可以作為原因的話,我覺得是因為你懶,給自己找了借口。據我自己學習,實踐總結,兩個框架都很簡單,有手就行,有腦就會,不見得會React就比Vue牛逼很多。其中都提供了相應腳手架,方便用戶使用:
Vue
npm install -g @vue/cli vue create my-project反應
npx create-react-app my-app cd my-app npm start傻瓜式使用,無限div就完事了。
大項目用React,小項目用Vue
這是我以前在華為的時候,內部討論兩個框架對比時下的一個標記。所謂呢?這個就是萬精油標注,沒有參考意義。你如何定義一個項目是大項目?超過xx萬行代碼?后端API超過xxx個?無論什么項目,都有做“大”的可能,只要正常運營,你就得持續維護,補充補充的需求。框架的可以替代更為重要。當然我可以這么跟你說,反應適度不適合“小”項目我不知道,但是Vue不適合“大”項目,業務代碼超過5萬行之后問題明顯,后面會詳細說這點。
XX大公司也在用Vue,我們跟隨就行了
很多新手在入門一些框架,或者選型組件,方案時會看看什么大公司已經用了,避免自己踩坑。當然啦,我也可以滴。但是大公司可能只是“嘗鮮”,“實驗性” ”使用,這些項目對他們彼此無關緊要,選型失敗了,壓力給到開發工程師,996糾正就行了,而你,╮(╯▽╰)╭項目和屎一樣也得維護下去。
舉個選型錯誤的例子,看看大公司怎么拯救的。
以前在華為做硬件項目的時候,用的原理圖軟件,那叫一個辣雞,用著用著總想砸掉電腦。歷史問題,選型錯誤,但無奈很多項目,基礎庫都在上面,只能硬著頭皮搞,遷移的成本太高,軟件廠商水平太差,但是華為牛逼啊,把那個軟件大改特改,各種內部數據庫都集成在上面,各種自開發的輔助工具,還是可以開發出很牛逼的產品,部門做的單板連續11年全球第一。
(PS:以前還用tcl寫腳本呢,你也可以試試蛋不蛋疼)- 如果你覺得你能搞定選型錯誤帶來的問題,或者你在華為,那當我們說。
Vue模板簡單,React jsx有學習成本
同上。兩個都很簡單,一學就會。連這點東東都叫學習成本,我只能說:“我不是針對你,我是說在座的各位都是…”(Vue的模板有很多工程實踐問題,后面詳說。)
性能對比
可以看看這個第三方基準測試,其中都都挺快的。不過我們實踐過程中發現有差異,大列表渲染,大量數據加載,不做進一步優化的話Vue明顯比React慢。TaskHub這個網站我們以前就是用Vue寫的,后來直接遷移到React前端性能大大提高,用戶體驗有明顯的差異(數據結構,后臺不變)。
深度對比
本來想簡單寫寫,沒想到前面寫了那么多了,╮(╯▽╰)╭,下面是重頭戲,寫寫實踐過程中發現的問題,兩個框架的解決思路。如果你還是小白,下面的一些東西可能沒接觸過,可以看下這篇文章:【譯】通過創建相同的APP,對比React和Vue,切實實現一下,了解基礎知識。
市場占比
相關npm下載量見上圖,市場已經用腳投票了。看到這里,如果你只想知道選型代表,你可以走了。如果你還說xx大公司在用Vue,跟著就行。可以這么說吧,大公司更多用的是React,用Vue更多的目的是保留相關技術棧能力,多一個選擇,避免React許可事件再次發生。
- React的許可協議到底發生了什么問題?
- Facebook認慫React專利,但問題依舊沒有解決?
當然,尤大也在這里說過,看npm下載量沒用,實際使用應該參考devTool的下載量。但是...為啥我打開的很多網站下面這個標都是亮的?
開發生態
客觀地說,作為核心團隊成員,意識到我們會更偏愛Vue,認為關于某些問題指向用Vue解決會更好。如果沒有這點信念,我們也就不會整天如此忙活了。但是在此后,我們想調整地公平和準確地來描述一切。其他的框架也有顯著的優點,例如React龐大的生態系統
由Vue官方
生態上的差異是明顯的,這點Vue官方也承認的,很多人因為生態這點遷移到React,不過我本人不是很在意,Vue生態也不差,如果說你用了React生態的東西就覺得很牛逼,你的核心也會用,這點并不能給你產品帶來多大增值,競爭力還是要靠自己手碼出來的好。下面簡單帶過:
UI組件
兩者的周邊UI庫都挺豐富的,反應稍微多一點,不過這不是選型的關鍵,自己手寫的UI庫也不是什么難事,偶爾封裝一下原生標簽也是很簡單的。以前用Vue的時候還沒有UI庫,手動寫了一個功能比較全的UI庫,用匯總打包,也就2萬行代碼左右,有手就行。
dom相關的第三方庫
Vue和React都有ref可以操作dom,自己封裝一下不是什么難事。可以找找有沒別人封裝好的,拿來主義。
- Vue:訪問子組件實例或子元素
- React:Refs和DOM
小程序(劃重點)
有小程序開發經驗的同學都知道,小程序原生開發是很蛋疼的,通常需要串行框架封裝,代碼轉換。常見的有幾個框架:
- 芋頭(React技術棧,推薦使用)
- wepy(Vue技術棧,強烈不推薦使用)
- uni-app(Vue技術棧,可以使用)
這些小程序開發框架都是基于Vue或React的二次封裝,簡化小程序開發。
vue的一些周邊庫和Vue強綁定,而不是一個獨立的js庫的形式存在。導致代碼難以理解,相關的Bug,問題也帶到了二次開發的框架中。
這種強依賴導致的問題會給以后項目升級,遷移帶來很多問題。比如vuex作為Vue的官方推薦的狀態管理方案,只能在Vue的上面使用,不能在陣營上面使用。Redux的狀態管理在陣營上用的多,這個卻能用在Vue之上。類似的問題很多,你會發現React周圍的東西可以用于Vue,Vue的東西不能用在React上。
如果你覺得這個問題不嚴重,當你把Vue代碼遷移到小程序wepy框架時發現,wepy不支持Vuex(bug異常多),狀態管理只能用redux,欲哭無淚。同樣的問題,如果你用的是React相關技術棧,反應遷移到Taro小程序框架異常簡??單,而且可以一次性生成微信小程序,支付寶小程序,字節跳動小程序等,代碼占用率高。
APP生態
weex,rn這塊我沒有比較好的實踐經驗,其中一些生產方案必須慎重考慮。rn比weex成熟這點是明確的。
邏輯代碼組織
Vue三種組件寫法對比(Js部分)
對象API 29行
import Vue, { PropOptions } from 'vue'interface User {firstName: stringlastName: number }export default Vue.extend({name: 'YourComponent',props: {user: {type: Object,required: true} as PropOptions<User>},data () {return {message: 'This is a message'}},computed: {fullName (): string {return `${this.user.firstName} ${this.user.lastName}`}} })API類17行
import { Vue, Component, Prop } from 'vue-property-decorator'interface User {firstName: stringlastName: number }@Component export default class YourComponent extends Vue {@Prop({ type: Object, required: true }) readonly user!: Usermessage: string = 'This is a message'get fullName (): string {return `${this.user.firstName} ${this.user.lastName}`} }功能API 25行
import Vue from 'vue' import { computed, value } from 'vue-function-api'interface User {firstName: stringlastName: number }interface YourProps {user?: User }export default Vue.extend({name: 'YourComponent',setup ({ user }: YourProps) {const fullName = computed(() => `${user.firstName} ${user.lastName}`)const message = value('This is a message')return {fullName,message}} })React兩種組件寫法對比(Js部分)
class組件34行
import React, { Component } from 'react';interface P {}interface S {}class Index extends Component<P, S> {constructor(props: Readonly<P>) {super(props);this.state = {};}static defaultProps = {};componentDidMount() {}componentDidUpdate(prevProps: Readonly<P>) {}componentWillUnmount() {}render() {return (<div></div>);} }export default Index;函數組件15行
import React, { FC } from "react";interface Props {}const Index: FC<Props> = (props) => {// js 代碼return (<div></div>); };Index.defaultProps = {};export default Index;在js邏輯部分其中寫法沒毛病,都需要用到框架特定的生命周期鉤子,Vue的類寫法最簡潔(3種對比),反應的功能寫法最清晰(全部寫法對比)。這部分不是選擇關鍵,怎么寫是個人喜好。
組件內狀態管理
Vue使用的是數據對象(數據),反應使用的是狀態對象(不可變狀態),這點兩個框架的設計不同,如下的問題解決思路也不同。
在組件狀態管理功能上兩者都沒有太多槽點,如果要說的話就是Vue watcher寫多了代碼一堆縮進,比較嚴重,反應也沒好多少。
Vue的寫法更加簡單,但組件狀態很多,需要明確的數據更新邏輯時,反應簡單的setState({} ,callback),就搞定了,Vue有點讓人摸不到頭腦。
Vue項目解決bug和疑難雜癥三大定理
沒有什么是deep watch解決不了的,有就加立即事件相關,dom相關記得nextTick實在不行,就用setTimeout
(來自某師兄)
React的不可變(immutable)狀態在應用復雜時表現出的透明,可測試性更佳。
以上內容對比下降,感覺兩者都OKOK的,功能也健全,Vue生態差一點,但是可以自己動手豐衣足食。以下是我們真正棄用Vue的原因。
沃蘇艾德布耀布耀德說過:同樣的問題,在語言層面上的解決方案才是最佳解決方案。語言生命周期長于框架生命周期
模板語法VS JSX
一部分丟失
Vue的單文件組件,使用<template>,<script>對代碼進行分割,直接導致的問題就是丟失。舉個例子,你封裝了一些常用的函數,在Vue文件中import進來。你這個函數能在template中直接使用嗎?
// filter.js 文件 export function isNickname(value) {return /^[\s\S]{1,50}$/.test(value); } <template><div>{{ a }}<button @click="a = isNickname('abc')">Test</button>{{ b }}</div> </template><script> // eslint-disable-next-line no-unused-vars import {isNickname} from '../fn/filter';export default {name: 'HelloWorld',props: { msg: String },data: () => {return {a: false,b: 1,c: 1,}},methods: {isNickname1() {return isNickname('abc');}} } </script><style scoped></style>上述代碼會報錯:
[Vue warn]: Property or method "isNickname" is not defined on the instance but referenced during render所以你只能將方法定義在methods中,再引用進來。模板語法并不知道你有isNickname這個函數,簡單的操作多了3行代碼。
模板語法不是圖靈完備的,必須轉換為js代碼(渲染函數),放在組件語境下才行。類似的例子還有很多,你會發現,你寫的代碼與Vue強綁定了,哪天Vue核心庫升級了,你代碼也崩潰了。Vue核心庫升級了,周邊依賴庫也得跟著升級。
模板分割
好的代碼組織能將常變與不變的部分進行分割解變量
Vue的模板嚴重限制了這一點。舉個例子,前端有個拖放菜單,功能不斷增加,而且對于不同的人要顯示不同菜單(權限管理)。在Vue中,為了實現html代碼(綁定在template)中)的分割,你只能再搞一個組件。在React中,可以直接這樣寫:
const menu = <div>abc<div>;可單獨做一個組件(低開銷函數組件),也可當做變量,放在當前代碼中。相對靈活很多。
JSX手寫渲染渲染函數自帶下面的優勢
- 完整的js功能來構建視圖頁面,可以使用臨時變量,js自帶的控制流,以及直接引用當前js作用域中的值
- 開發工具對jsx的支持比現有vue模板高級(linting,typescript,編譯器自動補全)
JSX可以用于Vue可以用于React,就像Redux一樣。這種語言是與框架解壓縮的。
“雖然模板語法有那么多問題,但是Vue也支持JSX呀。”
我猜到你會這么說,但就像上面所說的,既然我一定要用JSX / TSX,Redux了,那我為什么不用React?
“基于HTML的模板可以將現有的應用逐步遷移到Vue更加容易”
不會更容易,只會更麻煩。首先,下面會說到的模板中無法很好linting,type指示,代碼遷移過去很多bug無法及時發現。其次代碼遷移很大一部分都是js邏輯的遷移(這個更重要),遷移到vue中,你需要填鴨式細分原始代碼,放到計算,心態中,工作量不小且代碼和Vue強綁定。最后,原代碼類,@ click這些東西,有現代化的編輯器,批量替換成className,onClick不是很簡單的事情嗎?
打字稿,棉絨支持
這點更是致命,Typescript已成為我們前端開發的必需品。前就能發現大量錯誤。
而Vue的模板不支持typescript(官方還在增強),在模板上支持要很多“ hack”操作,原始框架更為復雜。Vue.extend對象中編寫代碼很難有比較好的ts,從而更好的支持Typescript,我們以前都是使用Vue的類寫法(參考上文)。前端配合后臺放置接口,而很多未提前檢查出的錯誤都出現在模板代碼中。
可測試性,重構
Vue需要新建一個.vue文件
<template><div>{{hello}}</div> </template><script> export default {name: 'Test',props: {hello: String},created() {console.log(this.hello);} } </script><style scoped></style>React操作都在jsx環境下執行,放的位置隨意,寫法比模板更容易測試,繼承:
function Test(props: { hello: string }) {console.log(props);return <div>{props.hello}</div> }Vue與React測試成本的差異明顯。React手起刀落,一個函數就搞定了,要測試什么內容清晰可見。類型,屬性修正就行了,編輯器自動化。
復雜狀態,動作管理
總體狀態管理方案選型是很重要的,畢竟95%以上的API對接代碼都在這里,這部分代碼占位代碼很大一部分,可以互換,替代,測試成為選擇的關鍵。
Vue推薦的方案只有將轉換的Vuex(Redux遷移到Vue等不算內部)React周邊方案有Redux,Mobx等。這些庫不會與React有太強的替換(可以獨立存在)。兩個框架的狀態管理思想差不多,都是單向數據流,單例模式(Vuex&Redux)。
威克斯
Vuex的源碼不多,可以看這里。可以看到代碼中有很多和Vue強綁定的東東,脫離了Vue,這東西就沒法用了。你可能會說我就用Vue,什么React不去用不就完了?考慮以下場景:
- 項目經理要把Vue的代碼遷移支持小程序,突然!有的框架不支持Vuex,腦袋嗡嗡嗡叫
- 項目經理說要設配APP端,突然!一堆臭蟲!腦袋嗡嗡叫
- 項目經理腦抽,要把React項目遷移到Vue,突然!redux!用的還是saga!腦袋嗡嗡叫
- 狀態管理出現靜態問題!要寫一堆爛碼去解決。新人看了腦袋嗡嗡叫
這部分的代碼比Vuex源碼都多?這些問題都是狀態管理庫和框架強綁定導致的,框架上的問題也會影響到周邊庫。
if (version >= 2) {Vue.mixin({ beforeCreate: vuexInit })} else {// override init and inject vuex init procedure// for 1.x backwards compatibility.const _init = Vue.prototype._initVue.prototype._init = function (options = {}) {options.init = options.init? [vuexInit].concat(options.init): vuexInit_init.call(this, options)}}可以看到,Vue核心升級,這些伴隨的庫也得升級,測試。在非瀏覽器環境下運行時,由于Vue(或類Vue框架)的初始化等機制需要體積,會導致相關庫,如Vuex不可用,多了一個代碼分支,相關代碼無法替換,測試,重構負擔重。
Redux
Redux是React上比較常用的狀態管理方案,其設計思想非常簡單(見上圖),可以獨立使用,相關代碼容易遷移到不同平臺。衍生出周邊替代方案也很多:
- 重擊式
- redux-promise
- Redux-Saga
- 可觀察到的
選型可以參考這里&這里,我們用saga比較多,處理靜態問題等比較簡單,起步多看看文檔就可以,也不難。下面這張圖可以幫助你理解幾個方案之間的關系,利弊權衡。
相關插件也很豐富,參考:Redux Middleware。你會發現很多你想要的東西Vuex都木有!
“既然這樣,我在Vue上用Redux就行了”
也行,畢竟這樣以后遷移到React會簡單點。
萬惡之源this指針
寫過React函數組件的同學都知道,引用類組件,函數組件少了this指針,代碼簡化,清晰多余。而這個問題在Vue上更為嚴重。
有人覺得這是優點,方便使用。等你代碼量上去了再來說話。
當項目多人協作的時候,或者承接某人某祖傳代碼,你不分段搜索,你都不知道這個上面掛了羊頭還是狗肉。
- 這個.ajax
- 這個.http
- 這條信息
- this.wtf…
正如一位網友評論:
那東西就是總體作用域。拿“允許在分成作用域上隨便放東西很方便”作為優點的話,和“允許隨地大小便會很方便”有什么區別……
寫C語言的新手都知道類別變量不要隨意用,這滿天飛的this,張三讀不懂,李四看不懂,IDE也不懂。而且這是官方推薦寫法,╮(╯▽╰)╭(說大規模不太準確,應該說是組件作用域)
想起我以前寫的Vue UI庫,叫SUE-UI,sue?很快的樣子。為了避免以后和其他插件沖突,插件使用都是:
- this。$ su_message
- this。$ su_modal
- 這個。$ su_toast
往事不堪回首啊!
最后
框架功能上,暫時沒有發現Vue做的來React做不來的事情,反過來也一樣,兩個框架都能滿足功能需求。工程實踐上,由于轉換性,代碼組織,粗略升級,測試,開拓讓我們最終放棄了Vue。
在Vue中你操作的是定義好的對象,React中你操作的是一個函數。所謂前端開發,本質就是在編寫下面幾個函數。
S = async(A1) S = sync(A2) UI = f(S)顯然,陣營對此的抽象更為徹底。
????資源獲取:
大家點贊、收藏、關注、評論啦 、查看👇🏻👇🏻👇🏻微信公眾號獲取聯系方式👇🏻👇🏻👇🏻
?精彩專欄推薦訂閱:在下方專欄👇🏻👇🏻👇🏻👇🏻
每天學四小時:Java+Spring+JVM+分布式高并發,架構師指日可待
總結
以上是生活随笔為你收集整理的为什么我们放弃了Vue?Vue和React深度比较的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文本处理工具命令xargs, sort,
- 下一篇: 国内vue这么火,为什么大厂都是用rea