Vue3 與 React 全方面對比
1. 編程風格 & 視圖風格
1.1 編程風格
React
語法少、難度大;Vue
語法多,難度小
例如指令:
Vue
<input v-model="username"/>
<ul>
<li v-for="(item,index) in list" :key="index">{{ item }}</li>
</ul>
React
<input value={username} onChange={e => setUsername(e.target.value)}/>
<ul>
{ list.map((item,index) => <li key={index}>{item}</li>) }
</ul>
Vue
給我們提供了很多的指令功能,而這些功能在 React
中基本都需要我們使用原生 js
來實現。
所以會有很多人說: "使用 Vue 實際上你就是在操作 Vue,使用 React 實際上你是在操作 js"。
- React 魔改少,手動實現;Vue 魔改多,自動完成。
例如事件:
Vue
<button @click="handleClick('hello')">點擊</button>
const handleClick = (msg) => {
console.log('msg')
}
React
<button onClick="handleClick('hello')">點擊</button>
const handleClick = (msg) => {
return () => {
console.log(msg)
}
}
像在點擊事件中傳參數這種功能:
-
我們知道
dom
的點擊事件是需要我們傳遞一個函數過去的,就像在React
中例子一樣,你的handleClick
肯定需要返回一個函數(或者在jsx
中寫箭頭函數調用handleClick
)。 -
而在
Vue
中可以在@click
中直接調用handleClick
函數,而這個函數又沒有返回一個新的函數,按道理這樣調用handleClick
是會返回undefined
的,但是由於Vue
底層做了魔改優化,使得我們不再需要在返回一個函數。
上面兩個例子中,我們說不上哪種好哪種不好,只能說你更喜歡哪一種。React
中的實現更符合 js
的邏輯但卻稍顯麻煩,Vue
中的實現簡單但卻沒有遵循原生 js
的特點。
編程風格上的總結:就像我們前面講的,Vue
寫起來更像是寫 Vue
代碼,React
寫起來更像是寫 JavaScript
代碼。
1.2 視圖風格
-
Vue
採用<template>
字符串模板。更貼近HTML
,學習成本低,但有時候不靈活。 -
React
採用JSX
語法,更類似於js
,限制比較多,(像一些關鍵字class
、for
,單標籤要閉合、屬性要駝峯、組件名要大寫等等這些都要注意),但是可以跟模板語法很好的進行結合
比如下面是一個通過 level
的值來渲染不同的標籤在 Vue
和 React
中的不同實現
Vue
<template>
<h1 v-if="level === 1">標題1</h1>
<h2 v-if="level === 2">標題2</h1>
</template>
React
let App = () => {
const level = 1
const Tag = 'h' + level
return (
<div>
{ <Tag>標題{level}</Tag>}
</div>
)
}
可以想象,如果當我們的條件判斷很多時,使用 JSX
的方式會比使用模版字符串要靈活的多。
注意: Vue
一開始並不直接支持 JSX
,在 Vue 2.1.0
版本中,Vue
引入了 render
函數來代替模板,這使得使用 JSX
作爲組件渲染函數成爲可能。在Vue 2.1.0
版本後的 create-vue
和 Vue CLI
都有預置的 JSX
語法支持。所以說在 Vue
中如果你想寫 JSX
這個它也是支持的,但是在 React
是沒辦法用字符串模板的方式寫。
2. 組件 & 路由 & 狀態管理
2.1 組件風格
-
Vue2
中採用 選項式 API,但是由於它不夠靈活,而且this
指向不夠簡單,Vue3
中給我們提供了 組合式 API 的寫法,組合式 API 更偏向函數式編程的方式,它的複用能力和組合的能力更強,而且沒有this
指向問題,也是Vue
比較推薦的寫法。 -
React
在16.8
版本之前都是採用類組件的方式開發,類組件也會有this
指向以及寫起來很繁瑣難度大的問題,在16.8
之後React
提供了函數組件的寫法,其實函數組件和Vue
的 組合式 API 是很像的,它的組合和複用的能力更強,而且也沒有this
指向問題,比類組件寫起來簡單很多,也是React
比較推薦的寫法
Vue 組件示意圖:
<template>
<div class="my-component">
<!-- HTML模板 -->
</div>
</template>
<script>
export default {
// JavaScript代碼
}
</script>
<style>
.my-component {
/* CSS樣式 */
}
</style>
React 組件示意圖:
import React from 'react';
import './MyComponent.css';
function MyComponent() {
// JavaScript代碼
return (
<div class>
{/* HTML模板 */}
</div>
);
}
export default MyComponent;
總結:這兩種框架它們的最終趨勢都是函數式編程,不管是 Vue
還是 React
都是推薦我們引入大量內置的函數或者是 use 函數來進行組合並且完成我們的開發需求。而簡化使用面向對象或者是配置的寫法,能簡化我們使用 this
的場景從而提升代碼的靈活度和簡易度。
2.2 路由風格
Vue
採用 Vue-Router
;React 採用 React-Router
相比而言 vue
語法更加簡練(useRouter useRoute),而 react
的 use 函數太多,不夠統一化(useLocation、useParams、useSearchParams、useNavigate......)
而像下面這些常規的功能它們都是大差不差的:
-
路由表的配置
-
嵌套路由
-
動態路由
-
編程式路由
-
守衛路由
Vue-Router 示例代碼
<!-- index.html -->
<div id="app">
<router-view></router-view>
</div>
// main.js
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import Home from './components/Home.vue'
import About from './components/About.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
})
const app = createApp({
// 空的 `setup` 函數
setup() {}
})
app.use(router)
app.mount('#app')
<!-- Home.vue -->
<template>
<div>
<h1>Home Page</h1>
<button @click="goToAbout">Go to About Page</button>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const goToAbout = () => {
router.push('/about')
}
</script>
<!-- About.vue -->
<template>
<div>
<h1>About Page</h1>
<p>Param: {{ $route.params.id }}</p>
<router-link to="/">Go to Home Page</router-link>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
const id = route.params.id
</script>
React-Router 示例代碼
import React from 'react'
import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } from 'react-router-dom'
import Home from './components/Home'
import About from './components/About'
const App = () => {
return (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
</ul>
<hr/>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
</div>
</Router>
)
}
const Home = () => {
const history = useHistory()
const handleClick = () => {
history.push('/about')
}
return (
<div>
<h1>Home Page</h1>
<button onClick={handleClick}>Go to About Page</button>
</div>
)
}
const About = () => {
const { id } = useParams()
return (
<div>
<h1>About Page</h1>
<p>Param: {id}</p>
<Link to="/">Go to Home Page</Link>
</div>
)
}
export default App
2.3 狀態管理風格
Vue
採用 Vuex/Pinia
;React
採用 Redux/Mobx
區別:
-
語法和
API
的不同:Vuex
和Pinia
是專門爲Vue.js
設計的狀態管理庫,因此它們的語法和 API 都非常類似。而Redux
和Mobx
可以在任何JavaScript
應用程序中使用,因此它們的語法和 API 與特定的框架無關。 -
數據流的不同:在
Redux
中,數據是通過單向數據流進行管理的,即action -> reducer -> store -> view
。而在Vuex
和Pinia
中,數據是通過Vuex store
或Pinia store
直接管理的,不需要reducer
。而在Mobx
中,數據則是通過響應式數據實現的。 -
異步處理的不同:在
Redux
中,異步處理通常需要使用中間件來處理異步操作。而在Vuex
和Pinia
中,異步操作可以通過actions
處理。而在Mobx
中,則可以使用async/await
或reaction
函數來處理異步操作。 -
開銷和複雜性的不同:
Redux
和Mobx
都需要在應用程序中進行額外的設置和配置,並且在處理大量數據時可能會導致性能問題。而Vuex
和Pinia
的設置和配置相對簡單,並且在大多數情況下可以處理大量數據。
總的來說,Vuex
和 Pinia
適用於 Vue.js
應用程序,提供了一種簡單和直接的狀態管理方式,而 Redux
和 Mobx
則可以在多種應用程序中使用,提供了更靈活的狀態管理方案。
Pinia 示例代碼
// store.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore({
id: 'counter',
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++
},
},
})
<!-- App.vue -->
<template>
<div>
<h1>Count: {{ count }}</h1>
<button @click="incrementCount">Increment</button>
</div>
</template>
<script setup>
import { defineComponent } from 'vue'
import { useCounterStore } from './store'
const counterStore = useCounterStore()
const count = counterStore.count
const incrementCount = () => {
counterStore.increment()
}
</script>
<!-- 在根組件中注入 store -->
<script>
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.mount('#app')
</script>
Redux Toolkit 示例代碼
// store.js
import { configureStore, createSlice } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: {
count: 0
},
reducers: {
increment(state) {
state.count++
}
}
})
export const store = configureStore({
reducer: {
counter: counterSlice.reducer
}
})
export const { increment } = counterSlice.actions;
// App.js
import { useSelector, useDispatch } from 'react-redux'
import { increment } from './store'
function App() {
const count = useSelector(state => state.counter.count)
const dispatch = useDispatch()
const incrementCount = () => {
dispatch(increment())
}
return (
<div>
<h1>Count: {count}</h1>
<button onClick={incrementCount}>Increment</button>
</div>
)
}
export default App
// 在根組件中注入 store
import { Provider } from 'react-redux'
import { store } from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
3. 一些基礎功能
3.1 模板對比
Vue
的視圖變化主要通過:指令 + 模板的方式
React
的視圖變化主要通過:原生 JS + 模板的方式
React
的模板比較強大,因爲可以編寫 JSX
結構,所以可以做出更加靈活的結構處理。
3.2 樣式對比
Vue
的 class
和 style
都有三種寫法:字符串、數組、對象
React
的 style
只能寫對象,class
只能字符串,可藉助 classnames
這個庫
兩個框架基本上都可以滿足常見的樣式需求。
3.3 事件對比
Vue
事件功能豐富
React
事件傳參需要高階處理
<!-- Vue -->
<template>
<ul>
<li v-for="item,index in list" @click="handleClick(index)"></li>
</ul>
</template>
<script>
methods: {
handleClick(index){
}
}
</script>
<!-- React -->
<ul>
{
list.map((v, i)=> <li onClick={handleClick(i)}></li>)
}
</ul>
const handleClick = (index) => {
return () => {
console.log(index)
}
}
3.4 表單對比
Vue
表單雙向綁定 v-model
React
表單受控與非受控
針對表單操作這一塊來說,Vue
的表單指令 v-model
還是非常靈活的,總體對比要比 React
使用方便且靈活。
3.5 組件通信對比
Vue
父子組件通過 props
屬性通信,子父組件通過 emits
方法通信
React
父子組件也是通過 props
屬性通信,而子父組件則是通過回調函數通信的
emits
自定義事件和回調函數,實際上是一樣的思想。
跨組件的通信方案也很類似,都是一種依賴注入的方式來實現的。
3.6 邏輯複用
Vue
選項式採用:mixins混入
;組合式採用:use函數
React
類組件採用:Render Props
、HOC
;函數組件:use函數
可以發現組合式 API 和函數組件都是採用 use 函數,所以基本複用是差不多的思想,這也是兩個框架推薦的用法。
3.7 內容分發
Vue
通過插槽,進行接收
React
通過 props.children
,進行接收
3.8 DOM 操作
Vue
通過 ref
屬性
React
也通過 ref
屬性處理
思路都是差不多的,就是給元素添加 ref
屬性,在跟對象或字符串綁定在一起,這樣就可以直接獲取到 DOM
元素。
4. 響應式 & 生命週期 & 副作用
4.1 響應式數據對比
Vue 採用響應式數據,底層通過 new Proxy() 進行監控,靈活性更高
React 採用 state 狀態,通過 setState() 方法進行內部 re-render,可控性更強
4.2 生命週期對比
Vue 生命週期鉤子 (常見)
-
beforeCreate
-
created
-
beforeMount
-
mounted
-
beforeUpdate
-
updated
-
beforeUnmount
-
unmounted
React 生命週期鉤子 (常見)
-
constructor
-
componentDidMount
-
componentDidUpdate
-
componentWillUnmount
-
render 整體對比來看,
Vue
的生命週期會更豐富一些,React
生命週期會更簡約一些。
4.3 副作用處理對比
vue 使用,watchEffect()
react 使用,useEffect()
都是處理副作用的方法,用法上還是有很大區別的。
watchEffect 會自動根據所依賴的值進行重渲染,而 useEffect 要明確指定對應的值才能進行重渲染,React 團隊已經給出在未來的版本中可能會改成根據所依賴的值自動進行重渲染的操作,但暫時還不行。
watchEffect 在更新前和卸載前觸發的方式是通過回調函數的參數被調用來實現的,而 useEffect 是通過 return 的返回值來指定的。
// Vue
watchEffect((cb)=>{
cb(()=>{
//更新前的觸發
})
})
// React
useEffect(()=>{
return ()=>{
//更新前的觸發
}
})
結語
作者:前端要努力 QAQ
鏈接:https://juejin.cn/post/7210918245993611301
來源:稀土掘金
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/MzEw2dpV5FAoeRQXrWaMXw