0
votes

I have a state object being passed through as a prop from another component. I receive the state as expected. I then store the props in a toRef() for reactivity.

What I want to happen is when the data in state changes, I want to data in the browser to update. As it is right now, the data does get updated in the vue dev tools and I do see the state object change but the browser does not reflect the changes until I manually refresh the browser, which is an undesired result.

Why is this happening:

Component:

<template>
      <div class="show-products">
        <Product
            v-for="data in products"
            :key="data.id"
            :product="data"
        />
      </div>
 </template>

<script>
import {computed, onMounted, toRefs, watch } from "vue";
import {useStore} from "vuex";
    
    export default {
      components: {Product},
      props: {
        state: Object
      },
      setup (props) {
        const store = useStore();
        const products = computed(() => store.getters.getProducts);
    
        let stateRef = toRefs(props).state;
    
        onMounted(() => {
          store.dispatch('getProducts');
        });
    
        watch(stateRef, (currentState, prevState) => {
          if (currentState.length !== prevState.length) {
            store.dispatch('getProducts');
          }
        })
    
        return {
          Product,
          products,
        }
      }
    }
</script>
1
maybe you could specify your props like this solutionwittgenstein
Don't set it to a ref and then watch the ref. Watch the prop directly like the above solution suggests.Klemen Tusar

1 Answers

1
votes

Observing the array length requires a deep watcher, so make sure to set the deep flag:

watch(stateRef, (currentState, prevState) => {/*...*/}, { deep: true })

Also, the watcher callback only receives the data references, so if you're only mutating the original array (e.g., via push() or pop()), the currentState and prevState arguments will be the same reference, which would defeat the length check for differences.

A potential solution is to remove the length check, and always dispatch the getProducts action in the watcher:

// ProductList.vue
watch(stateRef, (currentState, prevState) => {
  store.dispatch('getProducts')
}, { deep: true })

Another solution that does not require a deep watcher is to assign a new array to state instead of using push()/pop() on the original array:

// Parent.vue
addState(newValue) {
  state.value = [ ...state.value, newValue ]
}

demo