Subscribe on changes!

watchEffect is called twice on initialisation

avatar
Sep 16th 2020

Version

3.0.0-rc.11

Reproduction link

https://jsfiddle.net/qrh0ubaj/

Steps to reproduce

Consider this component

setup() {
  const price = ref(10);
  const history = ref<Array<string>>([]);
  watchEffect(() => {
    history.value.push(`Price changed to ${price.value}`);
  });
  return { price, history };
}

What is expected?

In rc.10, it only displays one change when initialised (Price changed to 10)

What is actually happening?

In rc.11, it displays this change twice.

avatar
Sep 16th 2020

Related to this: https://github.com/vuejs/vue-next/commit/5f4053967cb61620d3dd27518f571166d7b5ec8f Consider the following use cases, they can all reproduce the issue:

watchEffect(() => {
      // track
      price.value
      // trigger
      price.value = 20
});
watch(price, () => {
      // trigger
      price.value = 20
}, { immediate: true })  // immediate
avatar
Sep 16th 2020

As a supplement to what @HcySunYang pointed out, calling some methods can both trigger and track in one effect, which can lead to an infinite recursion in some scenarios.

e.g. Array.prototype.push, gets .length and sets values,

  const a = reactive([])

  const b = ref(0)
  const c = ref(0)

  watchEffect(() => {
    if (b < 10)
      a.push(1)
  })

  watchEffect(() => {
    if (c > -10)
      a.push(1)
  })
avatar
Sep 16th 2020

Oh, it was fixed while I was typing 😁