4

React和Vue是目前前端最主流的两大框架,最近面试总是被问及React和Vue的异同对比,这次就大概梳理一下。

GitHub上star对比截图

React
Vue

设计思想

React官网介绍React是一个用于构建用户界面的 JavaScript 库。React推荐JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即 ”all in js“,HTML和css都可以放到js中。React主张函数编程,推荐使用纯函数,数据不可变,单向数据流,但是可以手动编写onChange等事件处理函数实现双向数据流。结合JSX轻松实现渲染模板

Vue官网介绍Vue是一套用于构建用户界面的渐进式框架,与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue保留了html、css、js分离的写法,使得现有的前端开发者在开发的时候能保持原有的习惯,更接近常用的web开发方式,模板就是普通的html,数据绑定使用mustache风格,样式直接使用css。Vue认为数据是可变的,使用v-model实现双向数据流。

构建与调试

* 构建工具

React创建新的单页应用的最佳方式: Create React App

npx create-react-app my-app
cd my-app
npm start

Vue官方构建工具: vue-cli

npm install -g @vue/cli
vue create my-app
npm run serve
# OR
yarn global add @vue/cli
vue create my-app
npm run serve

* 调试

React Developer Tools用来调试react
Redux DevTools用来调试redux
Vue.js devtools用来调试vue,vuex等

JSX vs 模板

React没有模板,是通过类组件的render方法的返回值或者函数式组件的返回值来渲染虚拟DOM,通过原生js来实现条件渲染、循环渲染、插值等。也可以使用JSX语法糖来更简单地去描述树状结构;
Vue则是使用模板,模板更贴近HTML与js代码、css代码分离开,使用mustache进行数据绑定,使用指令来实现条件渲染、循环渲染等

数据变化监听

* 数据流对比


React是单向数据流,且是不允许子组件修改父组件传来的props,组件的state是允许修改的,可以通过setState(异步的)来进行更改,不允许通过this.state这种方式直接更改组件的状态。vue2.x中也不允许子组件修改父组件传递的props,组件与DOM之间可以通过v-model双向绑定

* 监听数据变化方式对比

React组件在调用setState后,默认情况下由于shouldComponentUpdate()里的返回值是true所以全部组件都会重新渲染,造成很多不必要的渲染,可以通过在组件的shouldComponentUpdate()生命周期方法中来进行渲染优化或者直接使用官方的PureComponent(shouldComponentUpdate()中进行状态和属性的浅比较来决定是否需要渲染)
Vue2.x中通过Object.defineProperty()把data对象中所有属性添加到vm上。为每一个添加到vm上的属性,都指定一个getter/setter。在getter/setter内部去操作(读/写)data中对应的属性。Vue3中通过new Proxy()和Reflect来为数据指定一个getter/setter。当设置数据的时候会触发对应的setter方法,从而进一步触发vm的watcher方法,然后数据更改,vm则会进一步触发视图更新操作。vue能够更加精确的知道数据变化,只重新渲染与变化数据绑定的DOM

事件

React通过属性来绑定事件,React类组件需要自己手动处理事件this指向的问题

        class Demo extends React.Component{
            /* 
                通过onXxx属性指定事件处理函数(注意大小写)
                        a.React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —————— 为了更好的兼容性
                        b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了的高效
             */
            constructor(props){
                super(props);
                //初始化状态
                this.state = {
                    number: 22
                }
                //解决this指向问题
                this.showInfo3 = this.showInfo3.bind(this)
            }
            
            showInfo1 = ()=> {
                console.log(this.state);
            }
            showInfo2 = (e, number)=> {
                console.log(number);
                console.log(this.state);
            }

            showInfo3() {
                console.log(this.state);
            }
            showInfo4(number) {
                return (e) => {
                    console.log(number);
                    console.log(this.state);
                }
            }

            render(){
                return(
                    <div>
                        <button onClick={this.showInfo1}>点我提示信息(不传参)</button>
                        <button onClick={this.showInfo3}>点我提示信息(不传参)</button>
                        <button onClick={(e) => {this.showInfo2(e,66)}}>点我提示信息(传参)</button>
                        <button onClick={this.showInfo4(88)}>点我提示信息(传参)</button>
                    </div>
                )
            }
        }

Vue中的事件处理函数都放到methods配置对象中,并把methods中的每一个事件处理函数都放到vm身上并把函数的this绑定到vm身上,通过指令来实现事件绑定

<button @click="showInfo1">点我提示信息(不传参)</button>
<button @click="showInfo2($event,66)">点我提示信息(传参)</button>

        const vm = new Vue({
            el:'#root',
            methods:{
                showInfo1(event){
                    console.log(this); //此处的this是vm
                },
                showInfo2(event,number){
                    console.log(this); //此处的this是vm
                    console.log(number); //66
                }
            }
        })

组件通信方式

React组件通信的几种方式:

  1. 父子组件通信:props
  2. 兄弟组件(非嵌套组件):消息订阅-发布(pubs-sub)、集中式管理(redux、dva)
  3. 祖孙组件(跨级组件):消息订阅-发布(pubs-sub)、集中式管理(redux、dva)、Context(生产者-消费者模式,用的少)

Vue组件通信的几种方式:

  1. 父子组件通信:props与自定义事件
  2. 兄弟组件(非嵌套组件):全局事件总线、消息订阅-发布(pubs-sub)、集中式管理(vuex、redux)
  3. 祖孙组件(跨级组件):全局事件总线、消息订阅-发布(pubs-sub)、集中式管理(vuex、redux)、provide/inject

生态对比

小程序

移动端App

其他对比

  • React认为数据不可变,所以一个嵌套比较深的状态数据obj:{a:{b:{c: '2'}}},修改obj.a.b.c = '3'是不会进行页面渲染的,只有this.setState({obj:{a:{b:{c: '3'}}}})才会进行页面渲染。Vue认为数据是可变的,但是只有data中初始化的数据才是响应式的,直接data中某个对象数据添加新数据是无法实现响应式的,得使用Vue.set(),对于数组,Vue不允许直接利用索引来修改数组可以使用Vue.set()或array.splice()
  • React使用高阶组件HoC来实现组件组合,vue则使用mixins来实现,由于vue默默帮我们做了这么多事,所以我们自己如果直接把组件的声明包装一下,返回一个HoC,那么这个被包装的组件就无法正常工作。React最早也是使用mixins的,不过后来他们觉得这种方式对组件侵入太强会导致很多问题,就弃用了mixins转而使用HoC。
  • React使用props、render props与children props来实现类似Vue中的具名插槽、作用域插槽和默认插槽
  • diff算法对比,React和Vue都只进行同层比较,且都是用key来优化diff算法。React中认为只要新旧虚拟DOM的标签名和key一样就是同一个虚拟节点,而Vue在标签名和key相同的基础上还要对比属性;Vue基于snabbdom库,使用双向链表,边对比,边更新DOM,React主要使用diff队列保存需要更新哪些DOM,得到patch树,再统一操作批量更新DOM。

Redux 与 Vuex对比

Redux原理图
react-redux原理图

  • Redux认为数据是不可变的,所以reducer中必须是纯函数,不允许修改传入的参数prevState,所以只能返回一个基于prevState的一个全新的state;
  • Redux中的action的值必须是一个一般对象,这也就注定Redux不能实现异步action(值为函数),但是可以使用中间件来实现异步action,常用的有redux-thunk、 redux-promise、redux-saga等;
  • Redux使用combineReducers(reducers)来实现模块化编码;
  • 使用react-redux的connect方法来创建容器组件把redux中的state、action传给UI组件的props中并实现监测redux中状态的改变并且重新渲染组件;

Vuex原理图

  • Vuex认为数据是可变的,所以不用像reducer那样的纯函数; Vue.use(Vuex)后创建完store,则vm上就添加了$store属性
  • Vuex中mutations是同步的,actions用来实现一些异步操作,当state中的数据需要经过加工后再使用时,可以使用getters加工;
  • mapState帮助我们映射state中的数据为计算属性;mapGetters用于帮助我们映射getters中的数据为计算属性;mapActions用于帮助我们生成触发actions的方法,即:包含$store.dispatch(xxx)的函数;mapMutations用于帮助我们生成触发mutations的方法,即:包含$store.commit(xxx)的函数;
  • 使用modules和namespaced来实现模块化

SuRuiGit
264 声望23 粉丝