vue和react对比(详解)
放两张图镇压小妖怪
本文先讲共同之处,
再分析区别
大纲在此:
共同点:
a、都使用虚拟dom
b、提供了响应式和组件化的视图组件
c、注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库。
区别:
a、优化
b、HTML&CSS
c、构建工具
d、数据绑定
e、状态管理
f、路由
g、渲染性能
h、数据更新
i、开发模式及规模
j、使用场景
k、服务器端渲染(SSR)
l、扩展(高阶组件和mixin)
1、都使用虚拟DOM
vue:Vue在2.0版本引入了vdom。其vdom是基于 snabbdom 库所做的修改。snabbdom是一个开源的vdom库。snabbdom的主要作用就是将传入的JS模拟的DOM结构转换成虚拟的DOM节点。先通过其中的 h函数 将JS模拟的DOM结构转换成虚拟DOM之后,再通过其中的 patch函数 将虚拟DOM转换成真实的DOM渲染到页面中。为了保证页面的最小化渲染,snabbdom引入了 Diff算法 ,通过Diff算法找出前后两个虚拟DOM之间的差异,只更新改变了的DOM节点,而不重新渲染为改变的DOM节点。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title></head><body> <p id="container"></p> <button id="btn-change">change</button> <!-- 引入snabbdom库,先不必纠结为什么这样引入,以及每个文件的作用。 --> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-class.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-props.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-style.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-eventlisteners.js"></script> <script src="https://cdn.bootcss.com/snabbdom/0.7.1/h.js"></script> <script> //定义patch函数 var patch = snabbdom.init([ snabbdom_class, snabbdom_props, snabbdom_style, snabbdom_eventlisteners ]) //定义h函数 var h = snabbdom.h; //生成一个vnode var vnode = h('ul#list',{},[ h('li.item',{},['Item 1']), h('li.item',{},['Item 2']), ]) //console.log(vnode); //获取container var container = document.getElementById('container'); patch(container,vnode);//初次渲染 var btn = document.getElementById('btn-change'); btn.onclick = function() { var newVnode = h('ul#list',{},[ h('li.item',{},['Item 1']), h('li.item',{},['Item B']), h('li.item',{},['Item 3']), ]) patch(vnode,newVnode);//再次渲染 vnode = newVnode;//将修改后的newVnode赋值给vnode } </script> </body> </html>
vue中的模板解析和渲染的核心就是:通过类似snabbdom的h()和patch()的函数,先将模板解析成vnode,如果是初次渲染,则通过patch(container,vnode)将vnode渲染至页面,如果是二次渲染,则通过patch(vnode,newVnode),先通过Diff算法比较原vnode和newVnode的差异,以最小的代价重新渲染页面。
react:react定义的一种类似于XML的JS扩展语法:XML+JS。
作用:用来创建react虚拟DOM(元素)对象。
//使用虚拟DOM import React from 'react' import ReactDOM from 'react-dom' import App from './App' import { BrowserRouter } from 'react-router-dom' import { Provider } from 'react-redux' import 'styles/reset.css' import 'styles/animate.css' import store from './store' ReactDOM.render( <Provider store={store}> <BrowserRouter> <App /> </BrowserRouter> </Provider>, document.getElementById('root') )
2、都提供了响应式和组件化的视图组件
3、都把注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库。(vue-router、vuex、react-router、redux等等)
4、优化
react:
在 React 应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。
如要避免不必要的子组件的重渲染,
你需要在所有可能的地方使用 PureComponent
,
或是手动实现 shouldComponentUpdate
方法。
react优化方法:
a、shouldComponentUpdate
b、immutable
可以看看:https://www.cnblogs.com/yangyangxxb/p/10104817.html
c、react-immutable-render-mixin,实现装饰器简化很多写法
d、无状态组件
e、高阶组件
vue:
在 Vue 应用中,组件的依赖是在渲染过程中自动追踪的,
所以系统能精确知晓哪个组件确实需要被重渲染。
你可以理解为每一个组件都已经自动获得了 shouldComponentUpdate
,并且没有上述的子树问题限制。
Vue 的这个特点使得开发者不再需要考虑此类优化,从而能够更好地专注于应用本身。
5、HTML&CSS
react:
在 React 中,一切都是 JavaScript。
在 React 中,所有的组件的渲染功能都依靠 JSX。
JSX 是使用 XML 语法编写 JavaScript 的一种语法糖。
import React, { Component } from 'react' import { SearchContainer, SearchContent } from './styledComponent.js' import search from 'images/search.png' class Search extends Component { render () { return ( <SearchContainer> <SearchContent { ...this.props }> <img src={search} alt=""/> <span>想吃什么搜这里,川菜</span> </SearchContent> </SearchContainer> ) } } export default Search
vue:
vue是把html,css,js组合到一起,用各自的处理方式
Vue 设置样式的默认方法是单文件组件里类似 style
的标签。
<template> <div class="m-movie"> <div class="white-bg topbar-bg"> <div class="city-entry"> <router-link tag="span" to="/cities" class="city-name">北京</router-link> </div> <div class="switch-hot"> <router-link tag="div" to="/home/movies/intheater" active-class="active" class="hot-item">正在热映</router-link> <router-link tag="div" to="/home/movies/coming" active-class="active" class="hot-item">即将上映</router-link> </div> </div> <transition :name="transitionName"> <router-view class="movies-outlet"></router-view> </transition> </div> </template> <script> export default { data () { return { transitionName: '' } }, watch: { $route (to, from) { if ( to.meta > from.meta ) { this.transitionName = 'slide-left' } else { this.transitionName = 'slide-right' } } } } </script> <style lang="stylus" scoped> @import '~styles/border.styl' @import '~styles/variables.styl' .slide-right-enter-active, .slide-right-leave-active, .slide-left-enter-active, .slide-left-leave-active { transition: all 1s; } .slide-right-enter { opacity: 0; transform: translate3d(-100%, 0, 0); } .slide-right-leave-to { opacity: 0; transform: translate3d(100%, 0, 0); } .slide-left-enter { opacity: 0; transform: translate3d(100%, 0, 0); } .slide-left-leave-to { opacity: 0; transform: translate3d(-100%, 0, 0); } </style>
关于.vue文件怎么运行的可以看:
https://www.cnblogs.com/yangyangxxb/p/10094180.html
6、 构建工具
react:
构建:create-react-app 快速脚手架
creat-react-app优点 无需配置:官方的配置堪称完美,几乎不用你再配置任何东西,就可以上手开发项目。 高集成性:集成了对React,JSX,ES6和Flow的支持。 自带服务:集成了开发服务器,你可以实现开发预览一体化。 热更新:保存自动更新,让你的开发更简单。 全兼容性:自动处理CSS的兼容问题,无需添加-webkit前缀。 自动发布:集成好了发布成品功能,编译后直接发布,并且包含了sourcemaps功能。
npm install -g create-react-app
create-react-app my-app(自己的项目名称)
cd my-app
npm start
vue:
构建:vue-cli脚手架
yarn global add @vue/cli (vue/cli是webpack的二次开发)
7、数据绑定
vue:vue是双向绑定, Vue.js 最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统。所谓双向绑定,指的是vue实例中的data与其渲染的DOM元素的内容保持一致,无论谁被改变,另一方会相应的更新为相同的数据。这是通过设置属性访问器实现的。
Vue 的依赖追踪是【原理上不支持双向绑定,v-model 只是通过监听 DOM 事件实现的语法糖】
vue的依赖追踪是通过 Object.defineProperty 把data对象的属性全部转为 getter/setter来实现的;当改变数据的某个属性值时,会触发set函数,获取该属性值的时候会触发get函数,通过这个特性来实现改变数据时改变视图;也就是说只有当数据改变时才会触发视图的改变,反过来在操作视图时,只能通过DOM事件来改变数据,再由此来改变视图,以此来实现双向绑定
双向绑定是在同一个组件内,将数据和视图绑定起来,和父子组件之间的通信并无什么关联;
组件之间的通信采用单向数据流是为了组件间更好的解耦,在开发中可能有多个子组件依赖于父组件的某个数据,假如子组件可以修改父组件数据的话,一个子组件变化会引发所有依赖这个数据的子组件发生变化,所以vue不推荐子组件修改父组件的数据,直接修改props会抛出警告
思想是响应式的,也就是基于是数据可变的,通过对每一个属性建立Watcher来监听, 当属性变化的时候,响应式的更新对应的虚拟dom
react:react是单向数据流;react中通过将state(Model层)与View层数据进行双向绑定达数据的实时更新变化,具体来说就是在View层直接写JS代码Model层中的数据拿过来渲染,一旦像表单操作、触发事件、ajax请求等触发数据变化,则进行双同步。推崇结合immutable来实现数据不可变。 可以看看:https://www.cnblogs.com/yangyangxxb/p/10104817.html。react在setState之后会重新走渲染的流程,如果shouldComponentUpdate返回的是true,就继续渲染, 如果返回了false,就不会重新渲染,PureComponent就是重写了shouldComponentUpdate, 然后在里面作了props和state的浅层对比;
8、状态管理
react:redux
可以看看:https://www.cnblogs.com/yangyangxxb/p/10047648.html
vue:vuex
可以看看:https://www.cnblogs.com/yangyangxxb/p/10096540.html
9、路由
可以直接看这个,很详细react router @4 和 vue路由 详解(全):https://www.cnblogs.com/yangyangxxb/p/10066650.html
10、渲染性能
react:
React 的渲染建立在 Virtual DOM 上——一种在内存中描述 DOM 树状态的数据结构。当状态发生变化时,React 重新渲染 Virtual DOM,比较计算之后给真实 DOM 打补丁。
Virtual DOM 提供了函数式的方法描述视图,它不使用数据观察机制,每次更新都会重新渲染整个应用,因此从定义上保证了视图与数据的同步。它也开辟了 JavaScript 同构应用的可能性。
在超大量数据的首屏渲染速度上,React 有一定优势,因为 Vue 的渲染机制启动时候要做的工作比较多,而且 React 支持服务端渲染。
元素是构成 React 应用的最小单位。元素用来描述你在屏幕上看到的内容,与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的对象,React DOM 可以确保 浏览器 DOM 的数据内容与 React 元素保持一致。
我们用React 开发应用时一般只会定义一个根节点。但如果你是在一个已有的项目当中引入 React 的话,你可能会需要在不同的部分单独定义 React 根节点。我们将 元素传入一个名为 ReactDOM.render() 的方法来将其渲染到页面上,页面上就会显示该元素。
vue:
Vue 通过建立一个虚拟 DOM 对真实 DOM 发生的变化保持追踪。
vue渲染的过程如下:
new Vue,执行初始化
挂载$mount方法,通过自定义Render方法、template、el等生成Render函数
通过Watcher监听数据的变化
当数据发生变化时,Render函数执行生成VNode对象
通过patch方法,对比新旧VNode对象,通过DOM Diff算法,添加、修改、删除真正的DOM元素
11、数据更新
react:
React 元素都是immutable 不可变的。当元素被创建之后,你是无法改变其内容或属性的。一个元素就好像是动画里的一帧,它代表应用界面在某一时间点的样子。
根据我们现阶段了解的有关 React 知识,更新界面的唯一办法是创建一个新的元素,然后将它传入 ReactDOM.render() 方法
vue:
数据直接修改,响应式。
12、开发模式及规模
react:
React本身,是严格的view层,MVC模式
vue:
- Vue是MVVM模式的一种方式实现
- 虽然没有完全遵循 MVVM 模型,Vue 的设计无疑受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的简称) 这个变量名表示 Vue 实例。
13、使用场景
react:
a、构建一个大型应用项目
同时用Vue和React实现的简单应用程序,可能会让一个开发者潜意识中更加倾向于Vue。这是因为基于模板的应用程序第一眼看上去更加好理解,而且能很快跑起来。
但是这些好处引入的技术债会阻碍应用扩展到更大的规模。
模板容易出现很难注意到的运行时错误,同时也很难去测试,重构和分解。
相比之下,Javascript模板可以组织成具有很好的分解性和干(DRY)代码的组件,干代码的可重用性和可测试性更好。
Vue也有组件系统和渲染函数,但是React的渲染系统可配置性更强,还有诸如浅(shallow)渲染的特性,和React的测试工具结合起来使用,使代码的可测试性和可维护性更好。
与此同时,React的immutable应用状态可能写起来不够简洁,但它在大型应用中意义非凡,因为透明度和可测试性在大型项目中变得至关重要。
b、同时适用于Web端和原生APP
React Native是一个使用Javascript构建移动端原生应用程序(iOS,Android)的库。 它与React.js相同,只是不使用Web组件,而是使用原生组件。 如果你学过React.js,很快就能上手React Native,反之亦然。
它的意义在于,开发者只需要一套知识和工具就能开发Web应用和移动端原生应用。如果你想同时做Web端开发和移动端开发,React为你准备了一份大礼。
阿里的Weex也是一个跨平台UI项目,目前它以Vue为灵感,使用了许多相同的语法,同时计划在未来完全集成Vue,然而集成的时间和细节还不清楚。因为Vue将HTML模板作为它设计的核心部分,并且现有特性不支持自定义渲染,因此很难看出目前的Vue.js的跨平台能力能像React和React Native一样强大。
vue:
a、期待模板搭建应用
- Vue应用的默认选项是把markup放在HTML文件中。数据绑定表达式采用的是和Angular相似的mustache语法,而指令(特殊的HTML属性)用来向模板添加功能。
相比之下,React应用不使用模板,它要求开发者借助JSX在JavaScript中创建DOM。
b、期待应用尽可能的小和快
当应用程序的状态改变时,React和Vue都将构建一个虚拟DOM并同步到真实DOM中。 两者都有各自的方法优化这个过程。
Vue核心开发者提供了一个benchmark测试,可以看出Vue的渲染系统比React的更快。测试方法是10000个项目的列表渲染100次。
从实用的观点来看,这种benchmark只和边缘情况有关,大部分应用程序中不会经常进行这种操作,所以这不应该被视为一个重要的比较点。
但是,页面大小是与所有项目有关的,这方面Vue再次领先,它目前的版本压缩后只有25.6KB。
React要实现同样的功能,你需要React DOM(37.4KB)和React with Addon库(11.4KB),共计44.8KB,几乎是Vue的两倍大。
双倍的体积并不能带来双倍的功能。
14、服务器端渲染(SSR)
客户端渲染路线:1. 请求一个html -> 2. 服务端返回一个html -> 3. 浏览器下载html里面的js/css文件 -> 4. 等待js文件下载完成 -> 5. 等待js加载并初始化完成 -> 6. js代码终于可以运行,由js代码向后端请求数据( ajax/fetch ) -> 7. 等待后端数据返回 -> 8. react-dom( 客户端 )从无到完整地,把数据渲染为响应页面
服务端渲染路线:1. 请求一个html -> 2. 服务端请求数据( 内网请求快 ) -> 3. 服务器初始渲染(服务端性能好,较快) -> 4. 服务端返回已经有正确内容的页面 -> 5. 客户端请求js/css文件 -> 6. 等待js文件下载完成 -> 7. 等待js加载并初始化完成 -> 8. react-dom( 客户端 )把剩下一部分渲染完成( 内容小,渲染快 )
react:
React的虚拟DOM是其可被用于服务端渲染的关键。首先每个ReactComponent 在虚拟DOM中完成渲染,然后React通过虚拟DOM来更新浏览器DOM中产生变化的那一部分,虚拟DOM作为内存中的DOM表现,为React在Node.js这类非浏览器环境下的吮吸给你提供了可能,React可以从虚拟DoM中生成一个字符串。而不是跟新真正的DOM,这使得我们可以在客户端和服务端使用同一个React Component。
React 提供了两个可用于服务端渲染组件的函数:React.renderToString 和React.render-ToStaticMarkup。 在设计用于服务端渲染的
ReactComponent时需要有预见性,考虑以下方面。
选取最优的渲染函数。
如何支持组件的异步状态。
如何将应用的初始化状态传递到客户端。
哪些生命周期函数可以用于服务端的渲染。
如何为应用提供同构路由支持。
单例、实例以及上下文的用法。
vue:
Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将静态标记”混合”为客户端上完全交互的应用程序。
服务器渲染的 Vue.js 应用程序也可以被认为是”同构”或”通用”,因为应用程序的大部分代码都可以在服务器和客户端上运行。
服务器端渲染优势
- 更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
- 更快的内容到达时间(time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备。无需等待所有的 JavaScript 都完成下载并执行,才显示服务器渲染的标记,所以你的用户将会更快速地看到完整渲染的页面。通常可以产生更好的用户体验,并且对于那些「内容到达时间(time-to-content)与转化率直接相关」的应用程序而言,服务器端渲染(SSR)至关重要。
15、扩展(高阶组件和mixin)
react可以通过高阶组件(Higher Order Components--HOC)来扩展,而vue需要通过mixins来扩展
React刚开始也有mixin的写法,通过React.createClass的api,不过现在很少用了。
Vue也不是不能实现高阶组件,只是特别麻烦,因为Vue对与组件的option做了各种处理, 想实现高阶组件就要知道每一个option是怎么处理的,然后正确的设置。
mixin小介绍:
vue中提供了一种混合机制--mixins,用来更高效的实现组件内容的复用。最开始我一度认为这个和组件好像没啥区别。。后来发现错了。下面我们来看看mixins和普通情况下引入组件有什么区别?
组件在引用之后相当于在父组件内开辟了一块单独的空间,来根据父组件props过来的值进行相应的操作,单本质上两者还是泾渭分明,相对独立。
而mixins则是在引入组件之后,则是将组件内部的内容如data等方法、method等属性与父组件相应内容进行合并。相当于在引入后,父组件的各种属性方法都被扩充了。
单纯组件引用:
父组件 + 子组件 >>> 父组件 + 子组件
mixins:
父组件 + 子组件 >>> new父组件
作用:多个组件可以共享数据和方法,在使用mixin的组件中引入后,mixin中的方法和属性也就并入到该组件中,可以直接使用。钩子函数会两个都被调用,mixin中的钩子首先执行。
下面给大家介绍vue mixin的用法,具体介绍如下所示:
//mixin.js export default { data() { return { name: 'mixin' } }, created() { console.log('mixin...', this.name); }, mounted() {}, methods: {} }
使用:
vue文件中使用 import '@/mixin'; // 引入mixin文件 export default { mixins: [mixin] }
小结
总结一下,我们发现,
- Vue的优势包括:
- 模板和渲染函数的弹性选择
- 简单的语法及项目创建
- 更快的渲染速度和更小的体积
- React的优势包括:
- 更适用于大型应用和更好的可测试性
- 同时适用于Web端和原生App
- 更大的生态圈带来的更多支持和工具
- 而实际上,React和Vue都是非常优秀的框架,它们之间的相似之处多过不同之处,并且它们大部分最棒的功能是相通的:
- 利用虚拟DOM实现快速渲染
- 轻量级
- 响应式和组件化
- 服务器端渲染
- 易于集成路由工具,打包工具以及状态管理工具
- 优秀的支持和社区
参考1:https://blog.csdn.net/CystalVon/article/details/78428036 参考2:https://cn.vuejs.org/v2/guide/comparison.html 参考3:https://www.cnblogs.com/suihang/p/10098860.html
参考4:https://www.jb51.net/article/138757.htm