在vue中,为什么父组件的值改变后,过几毫秒子组件才能watch到prop的变化?附代码

已找到答案 :

vue官网-深入响应式原理-异步更新队列

https://cn.vuejs.org/v2/guide...

复现代码

下方代码放进html文件中可直接运行,点击改变age按钮,查看控制台变化

子组件接收age,父组件传入age,改变父组件的age,输出子组件的age,此时子组件的age值还未更新

我想要的结果是 父组件age改变后,调用子组件的printAge方法,输出的age值是父组件改变后的age值,为什么结果不是这样,prop的原理为什么不是这样?prop的原理是怎样的?这块逻辑prop的源码是如何实现的?

控制台输出:

父组件中的age值为:2

子组件中的age值为:1

父组件改变age值后:5毫秒,子组件才监控到变化,变化前age:1,变化后age:2,此时子组件中的age值为:2

父组件中的age值为:3

子组件中的age值为:2

父组件改变age值后:1毫秒,子组件才监控到变化,变化前age:2,变化后age:3,此时子组件中的age值为:3

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>proptest</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
    <h1>{{hello}}</h1>
    <button @click="ageChange">改变age</button>
    <age ref="age" :age="age"></age>
</div>
</body>
<script>
Vue.component('age', {
    props: ['age'],
    data() {
        return {
            ageChangeTime: 0
        }
    },
    methods: {
        printChildAge() {
            this.ageChangeTime = new Date().getTime()
            console.log('子组件中的age值为:' + this.age)
        }
    },
    watch: {
        age(val, oldVal) {
            console.log('父组件改变age值后:' + (new Date().getTime() - this.ageChangeTime) + '毫秒,子组件才监控到变化,变化前age:'
                + oldVal + ',变化后age:' + val + ',此时子组件中的age值为:' + this.age)
        }
    },
    template: '<div>年龄:{{age}}</div>'
})
const app = new Vue({
    el: '#app',
    data() {
        return {
            age: 1,
            hello: 'hello world'
        }
    },
    methods: {
        ageChange() {
            this.age++
            console.log('父组件中的age值为:' + this.age)
            //调用子组件,输出子组件中的age值
            this.$refs.age.printChildAge()
        }
    }
})

</script>
</html>
阅读 899
评论
    6 个回答

    只说说结果为什么是这样子

    请考虑如下同步代码,那下面的代码会发生什么?watch3遍吗?不,通常来说,用户并不更新中间变了什么值,值关心一次marcotask最后的值变成了什么样。

    this.age++
    this.age++
    this.age++

    所以vue是怎么做的呢,放microtask里。scheduler.js#L176
    当然如果你需要同步更新子组件也不是不可以,加上Vue.config.async = false,但这个特性很快也会被移除。Vue-config-async-移除

      我理解着应该是子组件的age和父组件的age应该是同一个值,父组件值改变了,子组件瞬间改变

      那你理解错了,如果按你所说的父子组件的age指向同一个值的话,vue的子组件也不需要使用$emit()事件来跟父组件通讯了。至于vue为什么要这么做,好像教程里也有写。

      单向数据流
      所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

      额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

        • 94

        楼主, 他们是不可能同步的, 你别想了, 就算显示了0ms, 其实也是有时间的. 只是时间较少而已!
        单线程, 永远不可能同步, 它永远只能做完一件之后在做另一件

          5ms还不满足吗...

            "我理解着应该是子组件的age和父组件的age应该是同一个值"我觉得你想说的应该是 子组件的age和父组件的age应该是同一个变量,这在vue中是不允许的,如果父子组件用的是同一个变量的话父组件如何知道变量的值是被父组件改变的还是被子组件改变的?

              • 2
              • 新人请关照

              当然需要时间,不管怎么样,你当前的那个流程要走完才能走其他的awiat/Promise/interval/tiemout

                撰写回答

                登录后参与交流、获取后续更新提醒