组件props引用类型的字面量传值触发computed和watch的坑

2018.1.17补充说明

纠结的问题终于被解决了

引起这个坑的原因是父组件,父组件foo的数据更新后,模板里调用了foo,导致子组件虚拟节点被 re-render

坑终于被填上了。

之前的内容

标题很绕,我也不知道我在说什么

先来看两个父子组件:

父组件

<template>
  <child-component :foo.sync="foo" :bar="[]"/>
</template>
data () {
  return {
    foo: []
  }
}

子组件

<template>
  <Button @click="$emit('update:foo', [])">emit</Button>
</template>
props: {
  foo: Array,
  bar: Array
}
  • 子组件接受foobar两个props,类型都是Array(引用类型)
  • 子组件通过点击按钮向父组件emit事件,给父组件的foo重新赋值一个空数组
  • 父组件bar是通过字面量传值

于是乎,坑爹的地方来了

此时,我们在子组件里watch bar的变化

watch: {
  bar (val) {
    console.log(val)
  }
}

bar是父组件通过字面量传入进来的,理论上不会有任何变化,但每点击一次,都会触发watch,控制台会打印bar的值,每次都是一样的空数组

我们修改下父组件,不通过字面量,而是data里显式声明了bar

<template>
  <child-component :foo.sync="foo" :bar="bar"/>
</template>
data () {
  return {
    foo: [],
    bar: []
  }
}

这时watch没有被触发(计算属性同理)

总结:

  • 组件props尽量用值类型
  • 引用类型不要用字面量
  • props其它的引用类型的改变会触发字面量prop的计算和watch(foo改变了但却触发了bar的重新计算)
  • 这算不算是vue的底层bug?