vuejs / rfcs

RFCs for substantial changes / feature additions to Vue core
4.87k stars 546 forks source link

watchEffect as a component API #200

Open privatenumber opened 4 years ago

privatenumber commented 4 years ago

watchEffect is introduced via Composition API in Vue 3 (and to Vue 2 via composition-api plugin), and offers the convenience of being able to use the callback function to automatically determine reactive dependencies.

watchEffect(() => console.log(count.value))

I'm wondering if it could be officially supported in Vue 2 & 3 without the Composition API.

(I'm not against the composition API, but seems like this could be a stepping stone to some of the new features in v3.)

Motivation

It's currently cumbersome to add a shared handler that reacts to multiple props. Especially knowing that Vue can detect reactive dependencies for you.

This can be solved with watchEffects in the composition API, but would be nice to use this feature without the composition API.

export default {
    props: {
        value: Number,
        min: Number,
        max: Number,
    },

    watch: {
        value: 'validateProps',
        min: 'validateProps',
        max: 'validateProps',
    },

    methods: {
        validateProps() {
            assert(this.min < this.max, 'min must be smaller than max');
            assert(this.min < this.value, 'value must be greater than min');
            assert(this.max > this.value, 'value must be smaller than max');
        }
    }
}

API ideas

Support array in watch

By supporting an array to be passed into watch, functions can be passed in watchEffect style. The current object syntax for watch can still be passed in as an element of the array.

export default {
    props: {
        min: Number,
        max: Number,
    },

    // Add support for passing in an array
    watch: [
        function () {
            assert(this.min < this.max, 'min must be smaller than max');
        },

        // Current object-style watch for watching specific properties
        {
            max() {}
        }
    ]
}

watchEffect property

A new watchEffect property can be added to the component API to take in watchEffect functions. In v3, there's both watch and watchEffect so it makes sense to keep this separation.

export default {
    props: {
        min: Number,
        max: Number,
    },

    // new property
    watchEffect: [
        function () {
            assert(this.min < this.max, 'min must be smaller than max');
        },
    ]
}
{
    watchEffect: [

        // invoke immediately
        {
            immediate: true,
            handler() {
                assert(this.min < this.max, 'min must be smaller than max');
            },
        },
    ]
}

Alternatives


I can put together a formal RFC if there's interest in this.