Subscribe on changes!

Multiple source watcher fires sideEffect every time after watching sources has been evaluated

avatar
Apr 11th 2021

Version

3.0.11

Steps to reproduce

  • App.vue
<template>
    <child :foo="foo"></child>
</template>

<script lang="ts">
import { reactive } from 'vue';

import Child from './Child.vue';

export default {
    components: { Child },
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    setup(): any {
        const vm = (window.vm = reactive({
            window,
            foo: [false, false]
        }));

        return vm;
    }
};
</script>

<style scoped lang="scss"></style>
  • Child.vue
<template>
    <label>test</label>
</template>

<script lang="ts">
import { onBeforeMount, onMounted, reactive, onBeforeUpdate, watch, onUpdated } from 'vue';

export default {
    props: ['foo'],
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    setup(props: any): any {
        const vm = reactive({});

        onBeforeMount(() => {
            watch([() => props.foo.some((x: any) => x)], () => { console.log('mutated'); });
        });

        return vm;
    }
};
</script>

<style scoped lang="scss"></style>
  1. open console and add item into App's vm.foo by executing vm.foo.push(false);

What is expected?

Since before and after have same evaluation result: false, suppose sideEffect will not be fired.

What is actually happening?

The sideEffect has been fired and log message is displayed.


If we change the watcher line

from watch([() => props.foo.some((x: any) => x)], () => { console.log('mutated'); });

to watch(() => props.foo.some((x: any) => x), () => { console.log('mutated'); });

It works, same result before and after won't fired the sideEffect again.

How can I avoid this case if I really need to use multiple source watcher?