skip to Main Content

i am using vuejs3 with options api. as shown in the code posted below, i create a compsable class ClsUseStates.js, in which the value of state changes every second.
in app.vue, i instantiated an object of ClsUseStates and when the button in app.vue is clicked i call the method useStates to start generating the different states every second.

i wanted to reflect the changes or the different states occur in ClsUseStates in app.vue. to achieve that, in app.vue i created the variable state of type ref

the <span> state: {{ state }}</span> displays the changed states as suppose to be, when i run the code, and click the button, the text changes as follows:

started
processing
successful

but the problem i am facing is, the watch:{ state(oldval, newval) { console.log(oldval); console.log(newval); } } does not trigger the changes

please let me know why the changes in the value of state is not reflected in watch

i expect, that whin i click the button, to see the console.log shows the different values of state as well

ClsUseStates.js

import { ref } from 'vue'

export default class ClsUseStates {
    state = ref('not-satrted');
    constructor() {}

    useStates() {
        setTimeout(() => {
          this.setState('started')
        }, 1000);
      
        setTimeout(() => {
            this.setState('processing')
        }, 2000);
      
        setTimeout(() => {
            this.setState('successful')
        }, 3000);
    }

    setState(state) {
        this.state.value = state;
    }
    getState() {
        return this.state;
    }
}

app.vue

<template>
    <button @click="onDigitizePolygon()">
        click
    </button>
    <span> state: {{ state }}</span>
</template>

<script>
import {ref} from 'vue'
import ClsUseStates from './composables/ClsUseStates.js'

let cls = new ClsUseStates()
let state = ref('---')

export default {
  data() {
        return {
            state
        };
    },
  name: 'App',
  components: {
  },
  methods: {
    onDigitizePolygon() {
      cls.useStates()
      state.value = cls.getState()
    }
  },
  watch:{
    state(oldval, newval) {
      console.log(oldval);
      console.log(newval);
    }
  }
}
</script>

2

Answers


  1. Chosen as BEST ANSWER

    i think i found the answer. the watch option should have been looked like as follows. state.value must have been watched not state

    watch:{
    'state.value'(newVal, oldVal) {
      console.log(oldVal);
      console.log(newVal);
    },
    

    }


  2. The issue you’re facing is due to a subtle misunderstanding of Vue’s reactivity system.

    In your onDigitizePolygon method, you’re doing state.value = cls.getState(). What this does is set state.value to the ref returned by getState(), not the inner value of that ref.

    That means state.value is now pointing to a completely different ref, but your component’s state is still bound to the original ref(‘—‘).

    So when cls updates its internal state, your component’s state isn’t pointing to that new ref, which is why your watcher never triggers.

    To fix this, you should point state.value to the inner value of the ref returned by getState.

    onDigitizePolygon() {
      cls.useStates()
      state.value = cls.getState().value
    }
    

    and

    watch: {
      'state.value': {
        handler(newVal, oldVal) {
          console.log(oldVal);
          console.log(newVal);
        },
        immediate: true
      }
    }
    

    Hope this helps! 🌷

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search