Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

简述Vue和React开发体验的异同(状态层) #2

Open
EasyTuan opened this issue Jul 8, 2021 · 0 comments
Open

简述Vue和React开发体验的异同(状态层) #2

EasyTuan opened this issue Jul 8, 2021 · 0 comments

Comments

@EasyTuan
Copy link
Owner

EasyTuan commented Jul 8, 2021

前言

接上篇文章,本文我们来聊聊对于状态这块,Vue和React有何异同。

state vs data

先说关键词命名,在Vue中,通过声明data来定义内部变量,data翻译为中文是数据的意思,这也符合Vue的整体设计,响应式数据,一个数据的变化,会引发一系列的关联动作。而在React中,则变成了关键词state,翻译过来为状态的含义,通过状态驱动视图的更新。

在Vue中,数据是响应式的,这个响应式包含两方面:

  • JS内存中的变量值发生变化,通知DOM进行绘制
  • DOM中元素内容发生变化,通知JS内存中的变量值改变

在实现上,Vue利用JS的API,实现了点运算符的重载,利用如v-model等显式声明,通过对DOM元素的监听,及时反馈至内存变量的更新。Vue的这种做法其实是有一定的性能损耗的,但是带来是开发者的低门槛、高效率。

React在状态更新这块采用的是显式声明(setState),状态更新后,调用render函数,通知DOM进行绘制,数据流的传递是单向的(当然想实现Vue中的反向更新也是简单的,只是官方并不提倡)

我们来看个简单的例子,实现input组件输入值的绑定:

Vue:
<template>
    <input type="text" v-model="value" />
</template>
<script>
    export default {
        data() {
            return {
                value: ""
            }
        }
    }
</script>

React:
function render() {
    const [value, setValue] = useState("");
    return (
       <input type="text" onChange={(e) => setValue(e.target.value)} />
    )
}

Vue可以通过v-model这个指令把数据进行了响应式关联,可以减少写监听回调的一部分代码,但事实上,Vue也可以写成这样:

Vue:
<template>
    <input type="text" :value="value" @input="setValue">
</template>
<script>
    export default {
        data() {
            return {
                value: ""
            }
        },
        methods: {
            setValue(e) {
                this.value = e.target.value;
            }
        }
    }
</script>

虽然真实开发中大家不会这么写,谁叫Vue已经提供了现成的指令了呢。

在Vue中,有一个比较好用的功能:computed,可以监听依赖项的改变而进行时时计算,比如我们想实现第三个输入框为前两个输入框的值,我们会这么写:

Vue:
<template>
    <input type="text" v-model="a" /> +
    <input type="text" v-model="b" /> =
    <input type="text" v-model="sum" />
</template>
<script>
    export default {
        data() {
            return {
                a: "",
                b: "",
            }
        },
        computed: {
            sum() {
                return this.a + this.b
            }
        }
    }
</script>

computed的依赖收集

写到这里的时候,我产生了一个好奇的点,sum函数的调用时机如何确定,直观反应是需要收集该函数的依赖项,在React中,直接会要求开发者传入一个deps数组,只要每次比较数组的引用地址就可以确定,而在Vue中并没有要求开发者声明。常见的依赖收集有以下两种方式

  • 静态词法分析
  • 执行函数后获取

静态分析会比较消耗CPU性能,举个例子:

computed: {
    sum() {
        const a = "x";
        const b = a;
        const c = b;
        return this[c] * 2
    }
}

很明显,这个函数的依赖是x变量,但是需要推到x变量需要依次推导 c => b => a => "x",如果里面涉及到循环引用还会更加复杂,显然Vue不会走这条路。那么执行代码呢,这条路貌似是可行的,因为在Vue中数据的读取操作可以被监听到,那么思路可以是:执行一次sum函数,完毕后取所有被调用get的变量,组成依赖项,查阅相关资料后,证明Vue也是这么做的。

如果代码写成这样的话:

computed: {
    sum() {
        if (Math.random() < 0.5) {
            return;
        }
        return this.a + this.b
    }
}

这种情况下,有一半的概率导致数据无法及时更新,因为是首次执行的时候确定依赖项的。如果想在React实现这个需求,可以自己封装自定义hooks,可以模拟实现computed的功能。

逻辑复用

再来谈谈逻辑的复用性,在React还没出Hooks之前,和Vue差不多,UI描述和逻辑是混在一起的,想抽也抽不出来。所以在平时开发中大部分场景都是复制代码的形式来做的,能做的一些事情也比较有限,比如抽工具库、精心设计一个组件的规格。在React Hooks出现后,这件事发生了一些变化,UI描述和逻辑天然被拆开了,逻辑的复用也变得顺理成章了。

总结

  • 从数据驱动UI上来说,React和Vue没有什么本质上的区别,状态改变通知UI层重绘,只是Vue会比较隐晦,React则通过setState显式调用

  • Vue面向开发者做了很多“小工具”,来帮助开发者提高生产效率

  • 从开发体验上来说,还是仁者见仁智者见智了,毕竟大家的编码习惯都受着很多因素的影响

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant