美文网首页前端
浅聊 React & Vue

浅聊 React & Vue

作者: BeautifulHao | 来源:发表于2019-07-11 09:55 被阅读0次
比较.jpg

没有对比就没有伤害,今天突发奇想想对Vue和React的使用体验进行一下总结,随便比较下两者。网络上对比两者比较的各种的文章一大把,众说纷纭。接触和使用Vue和React已经很长时间了,给自己最直接的感觉是:两者并没有太明显的差别,毕竟完成的是同一件事情(业务页面开发),但如果是先用Vue,再用React的,会发现之前感觉Vue那种模板化和数据视图分离的编码方式很先进很牛逼,而写熟了React的JSX语法,和组件化的思想,一下子又觉得React的哲学思想又先进一点。所以总结下来,好比饭局上喝红酒还是白酒,不同时期给人感觉不一样。下文,不带偏见的聊聊两者。

发展历史

百科一把:

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

Vue 是一套用于构建用户界面的渐进式JavaScript框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。

​ 从介绍来看,两个框架都是MVC模式的延续,或者叫改进。React更侧着于V,正如介绍的“React主要用于构建UI”,React更关心的是UI的组件化,而Vue则在MVC的基础上提出了MVVM的思想。

国内使用情况:

​ BAT主流使用React多一点,普通互联网和传统软件公司还是Vue多一点(没有统计数据支撑,属于笔者意淫)。

原理分析

Vue代码:

main.js

import Vue from 'vue'
import App from './App'

new Vue({
  el: '#app',
  components: { App },
  render: h => h(App)
})

App.vue

<template>
  <div id="app">
    <ToList />
  </div>
</template>

<script>
import ToList from './components/ToList'
export default {
  components: { ToList },
  name: 'App'
}
</script>

ToList.vue

<template>
  <div>
    <div>
      <input v-model="inputValue" />
      <button @click="handleSubmit">提交</button>
    </div>
    <ul>
      <li v-for="(item,index) of list"
          :key="index">
        {{item}}
      </li>
    </ul>
  </div>
</template>
<script>
export default {
  name: 'ToList',
  data () {
    return {
      inputValue: '', list: []
    }
  },
  methods: {
    handleSubmit: function () {
      this.list.push(this.inputValue)
      this.inputValue = ''
    }
  }
}
</script>

​ 虽然编写代码的时候分了三个文件,但是通过webpack的vue-loader等插件,最终build完,其实只生成了一个有效的JS文件:app.XXXX.js。可以这么理解,浏览器其实识别不了vue这样的文件的,浏览器能解析的就是js\html\css。vue内部的script部分我们可以理解,那么我们来分析分析template最终会变成什么样的格式。取消webpack混淆压缩插件:UglifyJsPlugin,最终抠出来的转换后脚本如下:

var ToList = {
    name: 'ToList',
    data: function data () {
        return {
            inputValue: '',
            list: []
        }
    },

    methods: {
        handleSubmit: function handleSubmit () {
            this.list.push(this.inputValue)
            this.inputValue = ''
        }
    }
}

var ToList_render = function () {
    var _vm = this
    var _h = _vm.$createElement
    var _c = _vm._self._c || _h
    //templete最终变成了js版本的vnode结构
    return _c('div', [
        _c('div', [
            _c('input', {
                directives: [
                    {
                        name: 'model',
                        rawName: 'v-model',
                        value: _vm.inputValue,
                        expression: 'inputValue'
                    }
                ],
                domProps: { value: _vm.inputValue },
                on: {
                    input: function ($event) {
                        if ($event.target.composing) {
                            return
                        }
                        _vm.inputValue = $event.target.value
                    }
                }
            }),
            _vm._v(' '),
            _c('button', { on: { click: _vm.handleSubmit } }, [_vm._v('提交')])
        ]),
        _vm._v(' '),
        _c(
            'ul',
            _vm._l(_vm.list, function (item, index) {
                return _c('li', { key: index }, [
                    _vm._v('\n      ' + _vm._s(item) + '\n    ')
                ])
            }),
            0
        )
    ])
}

​ 可以发现,template其实最终转换为用JS描述的Dom结构(ToList_render),而这个结构其实就是虚拟节点(虚拟Dom)。并且v-model这类指令的标签,Vue自动给我们注册了input事件,值发生变化后自动赋值给绑定的数据。页面加载后,通过ToList_render函数,虚拟DOM就把JS-DOM渲染到了真实的DOM。

​ 那么既然是MVVM,数据发生变化,怎么更新到标签控件呢。上面的代码当然不能解释,阅读Vue源码其实可以大致发现,Vue采用了一个JS方法:Object.defineProperty(),通过vm的data对象,代理了真实data,从而感知data的get和set,然后通过上面的虚拟dom,改变具体的标签值,再通过虚拟DOM库Diff到真实Dom。

MVVM.png

React代码

    /*
    1)拆分组件: 拆分界面,抽取组件
    2)实现静态组件: 使用组件实现静态页面效果
    3)实现动态组件
        ① 动态显示初始化数据
        ② 交互功能(从绑定事件监听开始)
     */
    // 应用组件
    class App extends React.Component {
      constructor (props) {
        super(props)
        // 初始化状态
        this.state = {
          todos: ['吃饭', '睡觉', '打豆豆']
        }
        this.add = this.add.bind(this)
      }
      add (todo) {
        const {todos} = this.state
        todos.unshift(todo)
        //更新状态
        this.setState({todos})
      }
      render () {
        const {todos} = this.state
        return (
          <div style={{color:'red'}}>
            <TodoAdd add={this.add} count={todos.length} />
            <TodoList todos={todos} />
          </div>
        )
      }
    }

    // 添加todo组件
    class TodoAdd extends React.Component {
      constructor (props) {
        super(props)
        this.addTodo = this.addTodo.bind(this)
      }
      addTodo () {
        // 读取输入数据
        const text = this.input.value.trim()
        // 查检
        if(!text) {
          return
        }
        // 保存到todos
        this.props.add(text)
        // 清除输入
        this.input.value = ''
      }
      render () {
        return (
          <div>
            <h2>Simple TODO List</h2>
            <input type="text" ref={input => this.input=input}/>
            <button onClick={this.addTodo}>Add #{this.props.count}</button>
          </div>
        )
      }
    }
    TodoAdd.propTypes = {
      add: PropTypes.func.isRequired,
      count: PropTypes.number.isRequired
    }

    // todo列表组件
    class TodoList extends React.Component {
      render () {
        const {todos} = this.props
        return (
          <ul>
            {
              todos.map((todo, index) => <li key={index}>{todo}</li>)
            }
          </ul>
        )
      }
    }
    TodoList.propTypes = {
      todos: PropTypes.array.isRequired
    }

    // 渲染应用组件标签
    ReactDOM.render(<App />, document.getElementById('root'))

​ 首先React入门解释就说明了一个问题,render函数里面返回的是一个JSX语法的代码,而JSX的作用就是用来描述html的DOM结构的,也就是说React在build的完后,其实JSX已经转换为JS结构的DOM描述。如果没法直观理解,可以参考下React官方介绍 jsx:

JSX.png

​ 那么页面加载完成后,ReactJS做的事情,似乎和Vue是一样的,把JS-Dom 挂载到真实页面,也就是Diff挂载。那么问题来了,React既然不是MVVM这类双向的数据绑定,自称是单向的,它单向又如何实现呢。第一次接触React,其实就发现了一个特点setState函数。个人感觉,这是一个设计局限问题,React没法像Vue那样自然的修改data的值,它为了实现数据变化改变视图,委婉的约定了改变数据用setState函数。其实setState里面就间接的完成了Vue里面的数据发生变化的感知过程(这当然是废话,用户直接调用函数去修改数据了,当然直接感知了)。setState里面重新通过render函数渲染了虚拟Dom,然后再diff更新到真实dom。React既然都委婉的采用了setState,那自然可以对setState下些功夫了,异步更新(队列式更新),合并更新,借此来宣称一些性能上的优化,当然也由此产生了各种不便和问题。

React-V.png

对比点

  • 数据驱动

都采用数据驱动视图的思想,上来就是data数据和state数据,让开发人员一目了然的明白,我们干的事情就是数据来驱动视图的变化,业务开发的核心是数据。

  • 模板&虚拟Dom

虽然虚拟Dom化,Vue从2.0版本才引入了虚拟Dom,但到目前为止两者这方面的思想是一致的。通过Template也好,或者JSX也好,做的同一件事情,把html标签搞成js描述的Dom结构。其实回头想想,也只能用javascript语言来描述这个dom。为啥?这样可以写很多逻辑在里面,而带逻辑的描述语言,在浏览器端时候也只有js合适。另外要配合差异化更新(diff),似乎也只有采用内存比较才高效。当然Diff算法,两者还是有差异的,但思想还是一样的。

  • MVVM&单向

我目前为止了解到的,React为啥只实现 了单向,可以理解为简单化,并非100%的数据都需要双向,而且单向的过程简单明了,况且开发人员可以自行实现双向绑定。而Vue的双向,就是MVVM的核心体现了,这是它的优势,当然的确也带来了很多便利,尤其是表单开发过程。

  • 组件化

说完MVVM和单向,组件化过程两者的确都实现了,但React的组件化才把组件的概念体现的淋漓尽致。甚至函数即组件的概念,能够直白的让开发员理解啥是组件。而Vue的组件明显是在MVVM的思想影响下形成的,少许牵强。说起组件化,不得不聊一点。开始学习React,发现到处都是js,连HTML标签也用js编写,会觉得变扭,但真正做项目写惯了,豁然感觉,这么写比Vue更直白,更爽。当然也正是因为组件化,React的难度比Vue大,比如ES6的类组件,什么高阶函数啊,入门过程比较漫长。

  • 代码风格
    Vue文件把html\js\css按照三块进行组织,这种风格把数据和视图分开的很直接,而React就一个JS,html部分只是Render函数的返回值(JSX),似乎感觉分离,但似乎有合在一起。所以站在代码风格角度Vue的感觉更合理,但站在组件化的角度React的合并又更贴切。

相关文章

  • 浅聊 React & Vue

    ​ 没有对比就没有伤害,今天突发奇想想对Vue和React的使用体验进行一下总结,随便比较下两者。网络上对比两...

  • vue & react的区别

    vue & react 参考: 个人理解Vue和React区别Vue和React的使用场景和深度有何不同? vue...

  • Vue和React

    我们来对比一下Vue,React,Angular Vue和React对比 Vue和React相同点 基于MVC模式...

  • vue对比react、Angular(转官方文档)

    vue对比react、Angular(转官方文档) React React 和 Vue 有许多相似之处,它们都有:...

  • react和vue初始化数组的通用写法

    以下的写法react和vue是一样的。 React的写法 vue写法

  • 前端面试-vue

    1.了解vue和react吗?介绍一下。 vue和react都是主流的框架。vue : 脚手架vue-cli、路由...

  • 前端面试题

    1.了解vue和react吗?介绍一下。 vue和react都是主流的框架。vue : 脚手架vue-cli、路由...

  • vue和其它框架的对比

    React、Vue、Angular比较 相同之处: React和vue: 使用Virtual Dom 提供响应式和...

  • 前端3大框架

    react vue angular

  • 细读 React | PureComponet

    今天来聊一聊 React.Component、React.PureComponent、React.memo 的一些...

网友评论

    本文标题:浅聊 React & Vue

    本文链接:https://www.haomeiwen.com/subject/whfrkctx.html