最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Computed property in Vue is not triggering a watch - Stack Overflow

programmeradmin2浏览0评论

According to this post, it shouldn't be a problem to watch a puted 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
        }
    },
    puted: {
        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 puted property like so:

puted: {
    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 piler gives me a warning: error: Unexpected side effect in "product" puted property

According to this post, it shouldn't be a problem to watch a puted 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
        }
    },
    puted: {
        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 puted property like so:

puted: {
    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 piler gives me a warning: error: Unexpected side effect in "product" puted property

Share Improve this question edited Jul 21, 2018 at 20:20 HJo asked Jul 21, 2018 at 19:53 HJoHJo 2,2602 gold badges25 silver badges31 bronze badges 9
  • What are you trying to achieve? There may be a more straightforward solution to your problem – Enrico Commented Jul 21, 2018 at 20:10
  • I've updated my post to more clearly display intent. I'm trying to get a product and set some inital data() that are bound to some form inputs. I could set values within the pute function but I get this annoying side effect warning in the piler. I believe it's bad practice to set properties in a get? – HJo Commented Jul 21, 2018 at 20:16
  • 1 You would need to use a watcher with immediate set in order to get your watcher to fire on the initial render. – Bert Commented Jul 21, 2018 at 21:14
  • 1 @HamishJohnson you don't use puted for that. Have a look at created/mounted vue.js hooks. Inside them you can load external data and attach it to the current data model – Enrico Commented Jul 22, 2018 at 0:52
  • 1 @Enrico Yeah I have to agree with you there - not really sure why I chose puted in this instance. Thanks – HJo Commented Jul 22, 2018 at 9:38
 |  Show 4 more ments

3 Answers 3

Reset to default 3

Try the following:

watch: {
    product: {
        immediate: true,
        handler(value) { 
            updateCode();
        }
    }
}

Accordingly to OP's ments, his intention is to get and load some initial data. The mon 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>

Your structure is a bit all over the place. product is a puted, so it runs whenever it's source values change. (You have no control over when it runs.) It shouldn't have side effects (assignments this.description, this.title), or trigger network requests.

The code in product is fetching your source data. This belongs in methods, linked explicitly to a user action or a lifecyle event.

Why do you need to copy your data (this.description = product.description in watch:product)? Vue works best when you have your data (your app state) outside Vue, in a global variable say. Then your Vue ponents just transparently reflect whatever the app state is at a given moment.

Hope this helps.

发布评论

评论列表(0)

  1. 暂无评论