skip to Main Content

example store:

const trigger = ref(true);
const prop = computed(() => {
  trigger.value;
  console.log('comp prop run'); // works!
  return some_big_object;
});

const doChange = () => {
   some_big_object[5000].text = 'abc';
   trigger.value = !trigger.value;
}

 return { prop, doChange }

in component if I call store.doChange, the computed function runs, but the component still displays the previous value (no updated)

if I change the return in computed function to return {... some_big_object}; then it updates everywhere!

It appears to be because Vue does some check for the value, if it has the same reference as the prev value, it will not re-render it…

Is there some other way around this? I’d like to avoid creating a copy of a large object.

2

Answers


  1. You can watch the trigger and update the component manually:

    VUE SFC PLAYGROUND

    import {defineStore} from 'pinia';
    import {ref,computed} from 'vue';
    
    const some_big_object = {5000:{}};
    
    export const useUserStore = defineStore('user', () => {
    
    const trigger = ref(true);
    
    const doChange = () => {
       some_big_object[5000].text = 'abc';
       trigger.value = !trigger.value;
    }
    
     return { some_big_object, doChange, trigger }
    
    })
    
    <script setup>
    
      import { createPinia, storeToRefs} from 'pinia'
      import { useUserStore } from './store'
      import {getCurrentInstance, watch } from 'vue';
    
      const pinia = createPinia()
        const self = getCurrentInstance();
      self.appContext.app.use(pinia)
      const store = useUserStore();
      watch(() => store.trigger, () => {
        self.ctx.$forceUpdate();
      });
    </script>
    
    <template>
        <div>{{  store.some_big_object }}</div>
        <button @click="store.doChange">do change</button>
    </template>
    

    Or you can insert the trigger into the template

    VUE SFC PLAYGROUND

    <script setup>
    
      import { createPinia, storeToRefs} from 'pinia'
      import { useUserStore } from './store'
      import {getCurrentInstance, watch } from 'vue';
    
      const pinia = createPinia()
        const self = getCurrentInstance();
      self.appContext.app.use(pinia)
      const store = useUserStore();
    
    </script>
    
    <template>
        <div>{{  (store.trigger, store.some_big_object) }}</div>
        <button @click="store.doChange">do change</button>
    </template>
    

    Or you can use the trigger as a key to re-render the part where the big object is used:

    VUE SFC PLAYGROUND

    <script setup>
    
      import { createPinia, storeToRefs} from 'pinia'
      import { useUserStore } from './store'
      import {getCurrentInstance, watch } from 'vue';
    
      const pinia = createPinia()
        const self = getCurrentInstance();
      self.appContext.app.use(pinia)
      const store = useUserStore();
    
    </script>
    
    <template>
        <div :key="store.trigger">{{ store.some_big_object }}</div>
        <button @click="store.doChange">do change</button>
    </template>
    
    Login or Signup to reply.
  2. computed() should calculate something, and in your case it just returns an object. In the example doChange you mentioned, changes some_big_object[5000], so calculate this property.
    You can also return some_big_object from the store if you need it:

    /* store.ts */
    import { ref, computed } from 'vue'
    
    export const useStore = () => {
    
      const trigger = ref(true);
      const some_big_object = ref<any>({
        666: { text: 'evil' },
        5000:{}
      });
    
      const prop = computed(() => {
        console.log('comp prop run'); // works!
        return some_big_object.value[5000];
      });
    
      const doChange = () => {
        trigger.value = !trigger.value;
        if(!some_big_object.value[5000].text) {
          some_big_object.value[5000].text = 'abs';
          return;
        }
        some_big_object.value[5000].text = some_big_object.value[5000].text.split('').reverse().join('');
        
      }
    
      return { prop, doChange, trigger, some_big_object }
    }
    
    
    /* App.vue */
    <script setup>
    import { useStore } from './store.ts';
    
    const { prop, doChange, trigger, some_big_object } = useStore();
    </script>
    
    <template>
      prop: {{ prop }}<br>
      trigger: {{ trigger }}<br>
      <button @click="doChange">doChange</button><br>
      {{ some_big_object }}
    </template>
    
    

    Vue SFC Playground

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