Search code examples
javascriptvue.jsvuejs2vuex

Computed property in Vue is not triggering a watch


According to this post, it shouldn't be a problem to watch a computed property. And yet my code isn't working.

<template>
    <div v-if="product" class="section">
        <form>
            <div class="control"><input type="text" class="input" v-model="title"></div>
            <div class="control"><input type="text" class="input" v-model="description"></div>
        </form>
    </div>
</template>

<script>
export default {
    data() {
        return {
            title: null,
            description: null
        }
    },
    computed: {
        product() {
            // const payload = { collection: 'products', id: this.$route.params.productId }
            // return this.$store.getters.objectFromId(payload)
            console.log('working')
            return { title: 'Awesome Title', description: 'Awesome Description' }
        }
    },
    watch: {
        product() {
            this.title = this.product.title,
            this.description = this.product.description
        }
    }
}
</script>

I'm expecting the watch to trigger when product is returned, but it doesn't.

I could set the properties in the computed property like so:

computed: {
    product() {
        const payload = { collection: 'products', id: this.$route.params.productId }
        const product = this.$store.getters.objectFromId(payload)
        this.title = product.title
        this.description = product.description
        return product
    }
}

But then the compiler gives me a warning: error: Unexpected side effect in "product" computed property


Solution

  • Accordingly to OP's comments, his intention is to get and load some initial data. The common way to achieve this behavior is to place it inside created or mounted vuejs lifecycle hooks.

    <template>
        <div v-if="product" class="section">
            <form>
                <div class="control"><input type="text" class="input" v-model="title"></div>
                <div class="control"><input type="text" class="input" v-model="description"></div>
            </form>
        </div>
    </template>
    
    <script>
    export default {
        data() {
            return {
                title: '',
                description: ''
            }
        },
    
        created() {
            this.getInitialData();
            this.foo();
    
            console.log("created!");
        },
    
        methods: {
            getInitialData: function(){
                const payload = {
                    collection: 'products', 
                    id: this.$route.params.productId 
                };
                var product = this.$store.getters.objectFromId(payload);
                this.title = product.title;
                this.description = product.description;
            },
            foo: function(){// ...}
        },
    }
    </script>