sunmaobin / sunmaobin.github.io

blog
https://github.com/sunmaobin/sunmaobin.github.io
174 stars 11 forks source link

VUE 3.0 学习探索入门系列 - vue2.x/React/vue3.x 简单横评(4) #76

Open sunmaobin opened 3 years ago

sunmaobin commented 3 years ago

1 Vue 回顾

Vue.js 是 渐进式 的 JavaScript 框架。什么是 渐进式(Progressive) ?就是由浅入深,一步一步的,为什么 Evan You 说 Vue.js 是渐进式的框架呢?

Vue.js 有啥特点呢?

当然,如果想更全面的了解 Vue,对比 React 和 Angular 等框架,可以看看这里的 横向对比

参考资料:cn.vuejs.org/v2/guide/

Vue2.x

Vue 自诞生开始,每一个大版本都在进步,相比 Vue1.x 而言,我们现在使用的 Vue 2.x 效果:

参考资料:juejin.im/entry/68449…

Vue3.x

相比 Vue2.x 而言,Vue3.x 的设计目标:

参考资料:img.w3ctech.com/VueConf2019…

Evan You 为什么制定 Vue3.x 的这些目标呢?可能大家要先了解下 Vue2.x 的现状。

2 Vue 和 React 逃不掉的话题

2.1 Vue 和 React 哪个更好?

总体一个观点:众口难调!

总体一个原则:没有绝对好的框架,也没有绝对差的框架。每个人还是从各方面(自身技术能力、团队技术基础、上手成本、项目特点)考虑,选择一款适合自己的框架为好。

以下是 Evan You 对 Vue 和 React 对比的自我评价:

了解详情:www.zhihu.com/question/30…

One more thing

补充一点 Evan you 对 Vue 和 Angular 对比的自我评价:

了解详情:www.zhihu.com/question/40…

2.2 Vue 对于 Ts 的支持不够友好?

总体评价:Vue2.x 支持显然跟 React 和 Angular 是有差距的。

以下是 Evan You 对 Ts 的自我评价:

了解详情:www.zhihu.com/question/31…

One more thing

另外 Evan You 当初为什么选择使用 Flow ,而不是直接上 Ts

看这里:www.zhihu.com/question/46…

2.3 Vue 更适合中小项目?

首先来看看知乎上的一个帖子,大家讨论的热火朝天:为什么react比vue更适合大型应用?

在我之前的面试中,当问到如何看待 React 和 Vue 这2个框架的时候,也有不少的人的回答是:Vue 适合中小项目,React 适合大型项目!

其实,在回答这个问题之前,大家首先得弄明白 “什么是中小项目?什么是大型项目?” 如果这个标准不统一,那大家争论是没有意义的。

就好比,什么是大前端?什么是前端工程化?这是我的理解

其实业界也没有太多定义,以下是个人观点(欢迎指正),大型项目满足其一就行:

除此之外,都应该算作中小项目。

如果按照以上标准划分大中小型项目的话,大家平时有机会接触到的大项目有多少呢?

更何况,为了降低风险,除非无法拆分,不然一般公司里面大型项目也会被拆分成多个中小项目落地。所以,我要说的是,大家没必要从这个角度来划分一个前端框架,意义不大。

只是从人们的认知里面,一般认为的大型项目会出现以下问题,比如:

好了,其实按我的理解,与其说是用项目大小来决定该选择哪个框架,不如从自身遇到问题出发衡量下适合自己的框架,因为以上问题不止大型项目的问题,所有项目都可能会遇到。

2.4 Vue3.x setup 和 React hooks 对比

Vue setup 的思路借鉴了 React hooks 的灵感,同时也解决了 hooks 存在的上面的问题。

参考资料:vue-composition-api-rfc.netlify.com/#comparison…

2.5 个人观点 React 对比 Vue

简单对比下 React 和 Vue(个人理解和翻阅相关资料,欢迎批量指正,不引战!轻点喷!):

  1. React 更加拥抱 函数式编程 的思想,函数是一等公民;而 Vue2.x 更像是面向对象编程,AOP(切面)思想体现明显,比如:Options 一堆钩子的设计。到底哪个更好?随着 Vue3.x 的发布,答案就明了(下文会说)!
  2. React 一直是 Facebook 大公司维护;Vue 是个人作品,虽然到现在为止有 20人左右 的核心参与者,但是看 Github 提交记录(vuejs/vue工程),绝大多数代码还是 Evan You 提交维护(90%以上),其他人主要负责生态中的其他系统。这个会不会影响你选择使用哪个框架呢?我觉得至少在 Vue2.x 时代的时候,肯定有一些大的团队会优先考虑稳定性,毕竟历史上烂尾的例子太多了(近在眼前的 Flow 不就是么?偷笑)。
  3. 上面有提到 React 结合 Ts 开发,约束更强,规矩更多,对项目的风险把控较高;而 Vue2.x 对 Ts 支持天生较弱(上面已经仔细说了,没办法压错宝!),所以,对于使用 Ts 就回不去的人来说,简直无法忍受!但也不是不能用,只是有些弱(就个你用了Mac,就再回不到Windows一样)。
  4. 性能方面,大多数情况下 不分伯仲,更何况谁会傻到一个页面for循环几万条数据?或者组件嵌套10层以上呢?如果遇到我觉得需要优化产品,或者重构架构。
  5. 为什么对于 Vue3.x 大家都觉得越来越像 React?那是由于 Vue3.x 面对当前不足,借鉴了 React 的一些优点,弥补了自己的不足,比如:函数式编程、Ts 支持!所以,他们越来越像!
  6. 最后,如果说 Vue2.x 是 Evan you 基于各大门派独辟蹊径的一个轻量级、低门槛上手的框架的话,Vue3.x 更像是一个基于 React,将函数式编程这个自由发挥的编程思想重新包装,推出 Composition API,使其更有章法,更加规范的一个框架。

关于 Vue3.x

经过了上面各种对比,我们回过头来再看看 Vue3.x 改进:

3.1 Options API 到 Composition API 的转变

这其实是由完全面向对象OOP的思路,到函数式编程的思想转变。

只不过说起函数式编程大家看看文档可能都知道概念,无非业务逻辑都是一个个函数实现嘛!但是,真让你在项目里自由发挥写那么多函数的时候,你该怎么写?(这可能也是大家觉得 React 不太容易上手的以一个缘故吧,喜欢被 Vue 安排的明明白白!)

于是结合着 Vue2.x 里面的 Options API,将以前完全按照AOP模式的Options API,细粒度拆分成细小的函数,然后统一放到 setup 这一个入口函数中调用!鸡贼!佩服!

这样做的3个好处:

  1. 既保留了 Vue2.x 中各个函数的功能,做到兼容
  2. 同时以小的函数形式被调用,更加灵活,更好维护,更好 tree-shaking
  3. 最后还能将大家头痛的不知道如何函数式编程的痛点,安排明白一些(Composition API)

可谓:一石三鸟

下面以示例的形式来解释下这个概念。

比如 Vue2.x 时对于一个独立组件:

开始只有简单的鼠标处理逻辑。

export default {
    data() {
        return {
            x: 0,
            y: 0
        }
    },
    mounted() {
        window.addEventListener('mousemove', this.update)
    },
    methods: {
        update(e) {
            this.x = e.pageX
            this.y = e.pageY
        }
    },
    destroyed() {
        window.removeEventListener('mousemove', this.update)
    }
}
复制代码

以上会存在什么问题呢?举例来说明:

随着时间的推移,这个组件可能会发展成如下的模样!

export default {
    data() {
        return {
            x: 0,
            y: 0,
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            g: 0,
            h: 0,
            i: 0,
            j: 0,
            k: 0,
            l: 0,
            m: 0,
            n: 0 // 算了写不下去了。。。总之 data 可能会有很多
        }
    },
    mixins: [
        a,
        b,
        c,
        d,
        e,
        f // 算了,写不下去了,总之为了拆分代码,mixins 已经让我写到吐了
    ],
    mounted() {
        window.addEventListener('mousemove', this.update)

        // TODO 接下来可能会有一堆页面渲染完成的逻辑在这里哦

        // 这里是业务逻辑1
        // if / else if / else

        // 下面是业务逻辑2
        // while 

        // 哎呀所有的事情,都需要在页面渲染完去做呀,没办法
        // switch

        // 算了,写不下去了。。。
        // 跑路。。。
    },
    methods: {
        update(e) {
            this.x = e.pageX
            this.y = e.pageY
        },
        // 下面有一堆方法等着你哦
        method1() {
            // 预留着,方法只能放到 methods 对象下啊
        },
        method2() {
            // 张三的注释
            // 一堆逻辑
        },
        method3() {
            // ... 跑路了。。。
        }
    },
    destroyed() {
        window.removeEventListener('mousemove', this.update)
    }
}
复制代码

大家看出来上面的代码的问题了么?因为大家必须在 Vue 规定的条条框框里面写东西,所以,尤其初学者,会把一个简单的组件,写到简直无法直视的地步!

那你可能要说了,以上代码是有很多解决办法的呀,比如下面2种常见的优化方案:

1、将这个文件拆分成多个子组件或者模块

比如:如果按模块拆分,可以把 data 拆分成一个js文件,methods 拆分成一个 js 文件,等等。这么做只是相当于把一堆代码打散而已,代码连贯性、可维护性方面,变得更糟了。

再比如:拆分成多个子组件,每个子组件实现一块逻辑!(这是强拆!)大家拆分组件的原则,肯定不是基于代码量去拆的吧!所以,这会让业务模块,变得支离破碎,难以理解和维护。

2、使用 mixins 提取公共代码

mixins 解决的是公共的代码混入复用,如果只是一个组件过于庞大,你拆分到 mixins 多个文件中,有啥意义呢?跟上面的强拆有啥区别?

更何况,即便有复用的代码,如果一个文件中引入 10个以上的 mixin 文件,里面的 data 可能会覆盖,methods 可能会覆盖,你知道哪个生效了?template 使用的变量,你知道来自哪里?

对于上面的示例,Vue3.x 的解决办法

定义独立文件 mouse.js

这个文件就只处理鼠标事件!业务和代码逻辑都在一起,好理解,易于维护。

import { ref, onMounted, onUnmounted } from 'vue'

export function useMousePosition() {
  const x = ref(0)
  const y = ref(0)

  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }

  onMounted(() => {
    window.addEventListener('mousemove', update)
  })

  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })

  return { x, y }
}
复制代码

main.vue 引入文件

这里的代码量也变的很少,很清晰。

import { useMousePosition } from './mouse'

export default {
  setup() {
    const { x, y } = useMousePosition()
    // other logic...
    return { x, y }
  }
}
复制代码

示例参考:vue-composition-api-rfc.netlify.com/#logic-extr…

如果遇到不同的业务模块,就单独到独立文件或者模块处理,然后引入即可,比如:

(下面的逻辑如果在 vue2.x 中还真不太好处理!)

export default {
  setup () {
    // Network
    const { networkState } = useNetworkState()

    // Folder
    const { folders, currentFolderData } = useCurrentFolderData(networkState)
    const folderNavigation = useFolderNavigation({ networkState, currentFolderData })
    const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData)
    const { showHiddenFolders } = useHiddenFolders()
    const createFolder = useCreateFolder(folderNavigation.openFolder)

    // Current working directory
    resetCwdOnLeave()
    const { updateOnCwdChanged } = useCwdUtils()

    // Utils
    const { slicePath } = usePathUtils()

    return {
      networkState,
      folders,
      currentFolderData,
      folderNavigation,
      favoriteFolders,
      toggleFavorite,
      showHiddenFolders,
      createFolder,
      updateOnCwdChanged,
      slicePath
    }
  }
}
复制代码

参考代码:vue-composition-api-rfc.netlify.com/#code-organ…

看了以上代码有啥感想?我自己的感受:

3.2 更好的支持 Ts

Vue2.x 写法:

import { Component, Prop, Vue } from 'vue-property-decorator'

@Component
export default class HelloWorld extends Vue {
  @Prop() private message!: string;

  data (): object {
    // this.message
  }
}
复制代码

Vue3.x 写法:

import { defineComponent } from 'vue'
export default defineComponent({
  props: {
    message: String
  },
  setup(props, context) {
    // setup 中无法使用 this 关键词

    // props.message
    // context.attrs
    // context.slots
    // context.emit
  }
})
复制代码

对比下,至少写法上更简单,而且不用在使用那么多的 装饰器 了!

3.3 其他

再回过头来看看 Evan You 对 Vue3.x 的目标定义:

更小

对比了 vue@3.0.0-alpha.8vue@2.6.11 这2个版本的未压缩版本的文件大小:

单纯从这2个独立的版本看,3.0还变大了!

所以,个人认为,真正要能变小,可能还是要放到工程化体系中,依赖编译器,比如:webpack,然后基于 3.0 这种函数式编程更好 tree shaking 的机制,最终打包编译后的效果而言。

更快

Vue3.x 以下重大变化:

参考地址:img.w3ctech.com/VueConf2019…

理论上性能上肯定要比之前好(至少 Proxy 就更高效一些),但是这个目前还不好验证,相信正式 Release 后续官方也会给出一些数据,同时圈内肯定也会有很多测试结果出炉。

开放更多底层功能

我觉得应该就是 API 更完善一些吧,比如:

Vue3.x 的生命周期新增了2个 Debug Hooks(用于调试的钩子函数):

参考:vue-composition-api-rfc.netlify.com/api.html#li…

更多的等后面在仔细梳理。

(本文完)