说下React和 Vue的区别
前言
面试时候,有没有面试官问你:"那你说下React 和 Vue 有什么区别?"
本文记录了一些小编自己经历的,对于两个框架让开发者感受最直观的区别
该学习了,童鞋!!!
一、编程风格 (Template)
Vue
使用基于 HTML 的模板语法,允许开发者直接在模板中使用指令和插值表达式
xml
<template>
<div>
<p>{{ message }}</p>
<button @click="handleClick">Click me</button>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, Vue!'
};
},
methods: {
handleClick() {
alert('Button clicked!');
}
}
};
</script>
<style>
// 样式
</style>
React
使用 JSX 语法,将 HTML 和 JavaScript 结合在一起,需要在代码中编写类似 HTML 的结构。
javascript
import React, { useState } from 'react';
function App() {
const [message, setMessage] = useState('Hello, React!');
const handleClick = () => {
alert('Button clicked!');
};
return (
<div>
<p>{message}</p>
<button onClick={handleClick}>Click me</button>
</div>
);
}
export default App;
二、指令功能 (Directives)
1、条件渲染
Vue
v-if
:用于条件性地渲染元素。它基于表达式的值来决定是否显示或隐藏元素。
ini
<div v-if="isShown">这个元素会根据 isShown 的值进行条件渲染</div>
React
在React中,可以使用条件语句(如if
、switch
)或三元表达式来实现条件渲染。
css
{isShown && <div>这个元素会根据 isShown 的值进行条件渲染</div>}
2、列表渲染
Vue
v-for:用于基于数组或对象的数据来循环渲染元素。它可以遍历数组或对象的每个条目,并为每个条目生成相应的元素。
css
<ul>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
React
使用map
函数来遍历数组或对象,并返回相应的元素。
xml
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
3、属性绑定
Vue
v-bind
(简写为 :
):用于动态地绑定属性或表达式到元素上。它可以将数据绑定到元素的属性、样式或其他特性上。
ini
<div v-if="isShown">这个元素会根据 isShown 的值进行条件渲染</div>
React
在React中,可以直接使用JavaScript表达式来动态地设置元素的属性
xml
<img src={imageUrl} alt={imageAlt} />
4、事件处理
Vue
v-on
(简写为 @
):用于监听DOM事件并触发相应的方法。它可以将方法绑定到元素的事件上,如点击、鼠标移入等。
ini
<button v-on:click="handleClick">点击我触发 handleClick 方法</button>
React
在React中,可以直接将事件处理函数指定为元素的属性。使用箭头函数或绑定this
来确保正确的上下文。
xml
<button onClick={handleClick}>点击我触发 handleClick 方法</button>
5、表单双向绑定
Vue
v-model:用于在表单元素和应用程序状态之间创建双向数据绑定。它可以将表单元素的值与Vue实例中的数据进行同步。
ini
<input v-model="message" type="text">
React
在React中,可以通过将表单元素的值与组件的状态(state)进行绑定,使用onchange事件来更新状态。
ini
<input value={message} onChange={(e) => setMessage(e.target.value)}
type="text" />
三、组件风格 (Components)
这里介绍 React16.8 后的 的 函数组件 和 Vue3.0 后的组合式API
React Hook
React Hook 是 React 16.8 版本引入的一项新特性,它能够让函数组件拥有类组件中的状态(state)和生命周期方法(lifecycle methods)等功能。React Hook 包括了多个钩子函数(hook functions),如 useState、useEffect、useContext 等,在函数组件中使用这些钩子函数可以实现一系列常见的功能,如管理组件内部的状态、处理副作用等。React Hook 的出现使得函数组件可以更加灵活地处理复杂的逻辑,同时也提供了一种清晰且可重用的代码结构,使得代码易于维护和扩展。
javascript
import React, { useState, useEffect } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Component did mount');
return () => {
console.log('Component will unmount');
};
}, []);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
export default Counter;
这个组件使用了useState钩子来保存并更新一个计数器的状态。当用户点击按钮时,计数器会增加,并且在 UI 中显示出来。该 Hook 接受初始状态作为参数,并返回当前状态和一个更新状态的函数。在此示例中,我们使用数组解构将状态值和更新函数分配给count和setCount变量。每次用户单击按钮时,我们用setCount函数更新count的状态。
Vue hook
Vue 3.x 开始引入了 Hooks API,用于在函数式组件中实现状态和生命周期的管理。类似于 React 中的 Hooks,Vue 的 Hooks API 包括 setup() 和一些预置的 hooks 函数,如 ref()、watch()、onMounted() 等等,可以让我们更方便地编写函数式组件,并且具有更好的性能表现。其中,setup() 函数会在组件创建之前被调用,它接收两个参数:props 和 context。在 setup() 函数内部,我们可以使用预置的 hooks 函数来定义响应式数据、监听数据变化、执行副作用等操作,最后返回一个对象,该对象中包含模板中所需要使用的数据和方法。
xml
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
import { ref, onMounted, onUnmounted } from 'vue';
export default {
name: 'Counter',
setup() {
const count = ref(0);
onMounted(() => {
console.log('Component mounted');
});
onUnmounted(() => {
console.log('Component unmounted');
});
const increment = () => {
count.value++;
};
return {
count,
increment
};
}
};
</script>
在这个示例中,我们使用了 Vue 3 的 setup 函数来定义组件的逻辑。通过 ref 函数,我们创建了一个响应式的变量 count,并将其初始值设为 0。然后,我们定义了一个名为 increment 的函数来增加 count 的值。
在模板中,我们显示了当前的 count 值,并在按钮上绑定了 increment 函数。当点击按钮时,count 的值会增加,同时视图也会自动更新以反映新的值。
四、路由风格 (Router)
Vue
采用 Vue-Router (4.X)
npm install vue-router
配置实现(vue 3.0)
router/index.js 创建路由器实例
javascript
import { createRouter, createWebHistory } from 'vue-router';
// 创建路由实例
const router = createRouter({
history: createWebHistory(), // 使用hash模式可以用createWebHashHistory
routes: [
{ path: '/', component: () => import('../pages/Home/index.vue') },
{ path: '/home', component: () => import('../pages/Home/index.vue') },
{ path: '/about', component: () => import('../pages/About/index.vue') },
// 更多的路由...
],
});
export default router;
main.js 路由配置
javascript
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index';
import './index.css'
const app = createApp(App);
app.use(router);
app.mount('#app');
App.vue 使用路由
xml
<div id="app">
<router-view></router-view>
</div>
跳转实现
声明式
Vue中,使用 <router-link>
组件来创建声明式导航链接,通过 to
属性指定目标路由的路径。
xml
<template>
<div>
<router-link to="/about">Go to About</router-link>
</div>
</template>
编程式
Vue 中,可以通过 vue-route中的useRouter方法,执行函数式导航,使用 router.push方法实现跳转。
tips: vue3.X 中的useRouter 相当于 vue2.X 的 this.$router
xml
<template>
<div>
<button @click="jump('/home')">home</button>
<button @click="jump('/about')">About</button>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router';
const router = useRouter()
const jump=(url = '')=>{
router.push(url)
}
</script>
React
采用 React-Router (6.X)
npm install react-router-dom
配置实现(react 18.2)
rouetr/index.js 创建路由器实例和路由配置
javascript
import React from 'react'
import { Routes, Route} from 'react-router-dom'
import Home from '../pages/home/index.jsx'
const Router = () => {
return (
<Routes>
<Route path="/home" element={<Home />}></Route>
</Routes>
)
}
export default Router
index.js 使用路由
javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import Router from './router/index';
import { BrowserRouter} from 'react-router-dom'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<Router />
</BrowserRouter>
</React.StrictMode>
);
跳转实现
声明式
React中,使用 <Link>
组件来创建声明式导航链接,通过 to
属性指定目标路由的路径
javascript
import { Link } from 'react-router-dom';
const Navigation = () => {
return (
<div>
<Link to="/about">Go to About</Link>
</div>
);
};
编程式
React 中,可以通过 useHistory
钩子来获取路由历史对象,并用 history.push
方法进行函数式导航。
javascript
import { useHistory } from 'react-router-dom';
const Navigation = () => {
const history = useHistory();
const navigateToAbout = () => {
history.push('/about');
};
return (
<div>
<button onClick={navigateToAbout}>Go to About</button>
</div>
);
};
五、状态管理 (Store)
这里区别在于,Vue 主推 Vuex 和 Pinia, React 偏向使用 Redux 和 Mobx。
Vuex
和 Pinia
是专门为 Vue.js
设计的状态管理库,因此它们的语法和API都非常类似。而 Redux
和 Mobx
可以在任何 JavaScript
应用程序中使用,因此他们的语法和API和特定框架没有关系。
Pinia (Vue)
依赖安装
shell
npm install pinia
main.js 创建引入Pinia实例
js
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
import router from './router/index';
import './index.css'
const app = createApp(App);
const pinia = createPinia();
app.use(router);
app.use(pinia);
app.mount('#app');
store/counter.js 创建状态存储模块
js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0 }
},
actions: {
increment() {
this.count++
},
},
})
Home/index.vue 组件中使用
xml
<template>
<!-- 直接从 store 中访问 state -->
<div>{{ counter.count }}</div>
<button @click="add">点我</button>
</template>
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
const add = () => {
counter.increment()
}
</script>
Mobx (React)
依赖安装
shell
npm install mobx mobx-react --save
store/counter.js 配置数据存储模块
js
import { makeAutoObservable } from 'mobx';
class CounterStore {
constructor() {
makeAutoObservable(this);
}
count = 0;
increment = () => {
this.count++;
}
decrement = () => {
this.count--;
}
}
const counterStore = new CounterStore();
export default counterStore;
Home/index.jsx 组件中使用
jsx
import React from 'react';
import { observer } from 'mobx-react';
import counterStore from '@/store/counter';
const Counter = observer(() => {
return (
<div>
<h2>Count: {counterStore.count}</h2>
<button onClick={counterStore.increment}>Increment</button>
<button onClick={counterStore.decrement}>Decrement</button>
</div>
);
});
export default Counter;
六、生命周期 (Life)
根据 创建 挂载 更新 销毁 四个阶段来进行
Vue (3.0)
示意图
初始化
1、setup()
在组件实例化时调用,用于设置组件的状态和响应式数据。
挂载
2、 onBeforeMount()
在组件挂载前调用,可以进行一些准备工作。
3、onMounted()
在组件挂载后调用,通常用于执行异步请求或订阅事件。
更新
4、onBeforeUpdate()
在组件更新前调用,可以进行一些准备工作。
5、onUpdated()
在组件更新后调用,通常用于处理更新后的 DOM 操作或执行一些副作用。
卸载
6、onBeforeUnmount()
在组件卸载前调用,用于清理定时器、取消订阅等操作。
7、onUnmounted()
在组件卸载后调用,用于执行一些清理工作。
React (18.0)
示意图
初始化
1、constructor()
组件实例化时调用,用于初始化状态和绑定方法
2、componentWillMount()
组件初始化时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改state。
挂载
3、 render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行。此时就不能更改state了。
4、componentDidMount()
组件渲染之后调用,只调用一次。
更新
5、componentWillReceiveProps(nextProps)
组件初始化时不调用,组件接受新的props时调用。
6、shouldComponentUpdate(nextProps, nextState)
组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候。需要注意的是,
shouldComponentUpdate()
返回true
,则组件将会重新渲染在使用shouldComponentUpdate()
方法时,开发者需要谨慎操作,确保逻辑正确,避免出现意外的渲染结果。
7、componentWillUpdata(nextProps, nextState)
组件初始化时不调用,只有在组件将要更新时才调用,此时可以修改state
8、render()
组件渲染
9、componentDidUpdate()
组件初始化时不调用,组件更新完成后调用,此时可以获取dom节点。
4、卸载
10、componentWillUnmount()
组件将要卸载时调用,一些事件监听和定时器需要在此时清除。
关于React函数组件
在 React 中,函数组件没有传统的生命周期方法,但是引入了 React Hooks 来管理函数组件的状态和副作用。Hooks 提供了一组函数,可以在函数组件内部使用来实现类组件中的生命周期功能。
以下是一些常用的 React Hooks,可以用来模拟生命周期行为:
useState
:用于在函数组件中创建和管理状态。useEffect
:在组件渲染完成后执行副作用操作,相当于类组件中的componentDidMount
、componentDidUpdate
和componentWillUnmount
的结合。useLayoutEffect
:在组件渲染完成后,DOM 更新之前执行副作用操作,类似于useEffect
,但在浏览器执行绘制之前同步执行。useContext
:用于访问 React 的上下文(Context)。useReducer
:类似于 Redux 中的reducer
,用于管理复杂的状态逻辑。useCallback
:用于缓存回调函数,以便在依赖项不变时避免重新创建回调函数。useMemo
:用于缓存计算结果,以便在依赖项不变时避免重新计算。useRef
:用于在函数组件的多次渲染之间存储可变值。
使用这些 Hooks,可以在函数组件中实现类组件的生命周期行为。例如,使用 useEffect
可以在组件挂载、更新和卸载时执行相应的副作用操作,使用 useState
可以创建和管理组件的状态。
注意函数组件的 Hooks 必须在函数组件的顶层调用,不能在条件语句、循环或嵌套函数中使用。这是为了确保 Hooks 的调用顺序始终保持一致。虽然函数组件没有传统的生命周期方法,但通过使用 React Hooks,可以在函数组件中模拟生命周期行为并实现相应的功能。
七、怎么选择 (choose)
1、编程风格来看,vue的模板语法贴近于 html,所以在学习初的时候更容易被接受。react的编写方式则是更灵活一些。
2、官方功能实现,Vue的魔改较多。是方便了统一?还是被限制住了?react功能实现除了基本的,都要自己造轮子。是灵活发挥?还是容易造成质量不一?
3、都是广泛被前端使用的主流框架之一, 只为更好更高效的实现前端效果。
用 合适
和 需求
两个词来形容多者间的选择关系,最好不过了。无非对于这个需求,刚好合适。
对于文章内容有什么指点,欢迎评论留言,也更加欢迎JYM留下更为深层次关于对比的看法。
最后,给JYM两个数据作为参考
下载累计
查询入口:npm-stat.com/
Vue 每月平均下载量 1700w 左右,2023 年累计下载量:199,055,201(2 亿)。
React 每月平均下载量 8500w 左右,2023 年累计下载量:1,025,630,896(10.2 亿+)
学习难度
vue 前期学习难度前期可能没那么大,后期的进度就要缓慢一点
react 前期学习难度可能大一些,后期的难度就越来越小