Open AnnGreen1 opened 3 months ago
React
Vue
例如指令:
<input v-model="username"/> <ul> <li v-for="(item,index) in list" :key="index">{{ item }}</li> </ul>
<input value={username} onChange={e => setUsername(e.target.value)}/> <ul> { list.map((item,index) => <li key={index}>{item}</li>) } </ul>
Vue给我们提供了很多的指令功能,而这些功能在React中基本都需要我们使用原生js来实现。
js
所以会有很多人说: "使用 Vue 实际上你就是在操作 Vue,使用 React 实际上你是在操作 js"。
例如事件:
<button @click="handleClick('hello')">点击</button> const handleClick = (msg) => { console.log('msg') }
<button onClick="handleClick('hello')">点击</button> const handleClick = (msg) => { return () => { console.log(msg) } }
像在点击事件中传参数这种功能:
我们知道dom的点击事件是需要我们传递一个函数过去的,就像在React中例子一样,你的handleClick肯定需要返回一个函数(或者在jsx中写箭头函数调用handleClick)。
dom
handleClick
jsx
而在Vue中可以在@click中直接调用handleClick函数,而这个函数又没有返回一个新的函数,按道理这样调用handleClick是会返回undefined的,但是由于Vue底层做了魔改优化,使得我们不再需要在返回一个函数。
@click
undefined
上面两个例子中,我们说不上哪种好哪种不好,只能说你更喜欢哪一种。React中的实现更符合js的逻辑但却稍显麻烦,Vue中的实现简单但却没有遵循原生js的特点。
编程风格上的总结:就像我们前面讲的,Vue写起来更像是写Vue代码,React写起来更像是写JavaScript代码。
JavaScript
Vue采用<template>字符串模板。更贴近HTML,学习成本低,但有时候不灵活。
<template>
HTML
React采用JSX语法,更类似于js,限制比较多,(像一些关键字class、for,单标签要闭合、属性要驼峰、组件名要大写等等这些都要注意),但是可以跟模板语法很好的进行结合
JSX
class
for
比如下面是一个通过level的值来渲染不同的标签在Vue和React中的不同实现
level
<template> <h1 v-if="level === 1">标题1</h1> <h2 v-if="level === 2">标题2</h1> </template>
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是没办法用字符串模板的方式写。
Vue 2.1.0
render
create-vue
Vue CLI
Vue2中采用选项式 API,但是由于它不够灵活,而且this指向不够简单,Vue3中给我们提供了组合式API的写法,组合式 API更偏向函数式编程的方式,它的复用能力和组合的能力更强,而且没有this指向问题,也是Vue比较推荐的写法。
Vue2
this
Vue3
React在16.8版本之前都是采用类组件的方式开发,类组件也会有this指向以及写起来很繁琐难度大的问题,在16.8之后React提供了函数组件的写法,其实函数组件和Vue的组合式 API是很像的,它的组合和复用的能力更强,而且也没有this指向问题,比类组件写起来简单很多,也是React比较推荐的写法
16.8
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 className="my-component"> {/* HTML模板 */} </div> ); } export default MyComponent;
总结:这两种框架它们的最终趋势都是函数式编程,不管是Vue还是React都是推荐我们引入大量内置的函数或者是 use 函数来进行组合并且完成我们的开发需求。而简化使用面向对象或者是配置的写法,能简化我们使用this的场景从而提升代码的灵活度和简易度。
Vue采用Vue-Router;React 采用React-Router
Vue-Router
React-Router
相比而言vue语法更加简练(useRouter useRoute),而react的 use 函数太多,不够统一化(useLocation、useParams、useSearchParams、useNavigate......)
vue
react
而像下面这些常规的功能它们都是大差不差的:
路由表的配置
嵌套路由
动态路由
编程式路由
守卫路由
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
Vue采用Vuex/Pinia;React采用Redux/Mobx
Vuex/Pinia
Redux/Mobx
区别:
语法和API的不同:Vuex和Pinia是专门为Vue.js设计的状态管理库,因此它们的语法和API都非常类似。而Redux和Mobx可以在任何JavaScript应用程序中使用,因此它们的语法和API与特定的框架无关。
API
Vuex
Pinia
Vue.js
Redux
Mobx
数据流的不同:在Redux中,数据是通过单向数据流进行管理的,即action -> reducer -> store -> view。而在Vuex和Pinia中,数据是通过Vuex store或Pinia store直接管理的,不需要reducer。而在Mobx中,数据则是通过响应式数据实现的。
action -> reducer -> store -> view
Vuex store
Pinia store
reducer
异步处理的不同:在Redux中,异步处理通常需要使用中间件来处理异步操作。而在Vuex和Pinia中,异步操作可以通过actions处理。而在Mobx中,则可以使用async/await或reaction函数来处理异步操作。
actions
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') );
Vue的视图变化主要通过:指令 + 模板的方式
React的视图变化主要通过:原生JS + 模板的方式
React的模板比较强大,因为可以编写JSX结构,所以可以做出更加灵活的结构处理。
Vue的class和style都有三种写法:字符串、数组、对象
style
React的style只能写对象,class只能字符串,可借助classnames这个库
classnames
两个框架基本上都可以满足常见的样式需求。
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) } }
Vue表单双向绑定v-model
v-model
React表单受控与非受控
针对表单操作这一块来说,Vue的表单指令v-model还是非常灵活的,总体对比要比React使用方便且灵活。
Vue父子组件通过props属性通信,子父组件通过emits方法通信
props
emits
React父子组件也是通过props属性通信,而子父组件则是通过回调函数通信的
emits自定义事件和回调函数,实际上是一样的思想。
跨组件的通信方案也很类似,都是一种依赖注入的方式来实现的。
Vue选项式采用:mixins混入;组合式采用:use函数
mixins混入
use函数
React类组件采用:Render Props、HOC;函数组件:use函数
Render Props
HOC
可以发现组合式API和函数组件都是采用use函数,所以基本复用是差不多的思想,这也是两个框架推荐的用法。
Vue通过插槽,进行接收
React通过props.children,进行接收
props.children
Vue通过ref属性
ref
React也通过ref属性处理
思路都是差不多的,就是给元素添加ref属性,再跟对象或字符串绑定在一起,这样就可以直接获取到DOM元素。
DOM
Vue采用响应式数据,底层通过new Proxy()进行监控,灵活性更高
React采用state状态,通过setState()方法进行内部re-render,可控性更强
Vue生命周期钩子(常见)
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
beforeUnmount
unmounted
React生命周期钩子(常见)
constructor
componentDidMount
componentDidUpdate
componentWillUnmount
render 整体对比来看,Vue的生命周期会更丰富一些,React生命周期会更简约一些。
vue使用,watchEffect()
react使用,useEffect()
都是处理副作用的方法,用法上还是有很大区别的。
watchEffect会自动根据所依赖的值进行重渲染,而useEffect要明确指定对应的值才能进行重渲染,React团队已经给出在未来的版本中可能会改成根据所依赖的值自动进行重渲染的操作,但暂时还不行。
watchEffect在更新前和卸载前触发的方式是通过回调函数的参数被调用来实现的,而useEffect是通过return的返回值来指定的。
// Vue watchEffect((cb)=>{ cb(()=>{ //更新前的触发 }) })
// React useEffect(()=>{ return ()=>{ //更新前的触发 } })
1. 编程风格 & 视图风格
1.1 编程风格
React
语法少、难度大;Vue
语法多,难度小例如指令:
Vue
React
Vue
给我们提供了很多的指令功能,而这些功能在React
中基本都需要我们使用原生js
来实现。所以会有很多人说: "使用 Vue 实际上你就是在操作 Vue,使用 React 实际上你是在操作 js"。
例如事件:
Vue
React
像在点击事件中传参数这种功能:
我们知道
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
React
可以想象,如果当我们的条件判断很多时,使用
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 组件示意图:
React 组件示意图:
总结:这两种框架它们的最终趋势都是函数式编程,不管是
Vue
还是React
都是推荐我们引入大量内置的函数或者是 use 函数来进行组合并且完成我们的开发需求。而简化使用面向对象或者是配置的写法,能简化我们使用this
的场景从而提升代码的灵活度和简易度。2.2 路由风格
Vue
采用Vue-Router
;React 采用React-Router
相比而言
vue
语法更加简练(useRouter useRoute),而react
的 use 函数太多,不够统一化(useLocation、useParams、useSearchParams、useNavigate......)而像下面这些常规的功能它们都是大差不差的:
路由表的配置
嵌套路由
动态路由
编程式路由
守卫路由
Vue-Router 示例代码
React-Router 示例代码
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 示例代码
Redux Toolkit 示例代码
3. 一些基础功能
3.1 模板对比
Vue
的视图变化主要通过:指令 + 模板的方式React
的视图变化主要通过:原生JS + 模板的方式React
的模板比较强大,因为可以编写JSX
结构,所以可以做出更加灵活的结构处理。3.2 样式对比
Vue
的class
和style
都有三种写法:字符串、数组、对象React
的style
只能写对象,class
只能字符串,可借助classnames
这个库两个框架基本上都可以满足常见的样式需求。
3.3 事件对比
Vue
事件功能丰富React
事件传参需要高阶处理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的返回值来指定的。