Dave
Dave

Reputation: 12487

Can you force Vue.js to reload/re-render?

Just a quick question.

Can you force Vue.js to reload/recalculate everything? If so, how?

Upvotes: 425

Views: 749450

Answers (24)

Duc Trung Mai
Duc Trung Mai

Reputation: 2598

As of 06/2024, (Vue 3.4.27), this is how you do forceUpdate (working example, can just copy paste)

<template>
  <div>
    <p>{{ message }} - {{ count }}</p>
    <button @click="updateMessage">Update Message</button>
    <button @click="updateCount">Update Count</button>
    <button @click="forceUpdateComponent">Force Update</button>
  </div>
</template>

<script setup>
import { ref, getCurrentInstance } from 'vue';

const message = ref('Hello, World!');
const { proxy } = getCurrentInstance();
let count = 1

function updateMessage() {
  message.value = 'Hello, Vue 3!';
}

function updateCount() {
  count++
}

function forceUpdateComponent() {
  proxy.$forceUpdate();
}
</script>

Upvotes: 2

Dagg M.
Dagg M.

Reputation: 68

this.$router.go()

this.$forceUpdate(); doesnt work with Vue3

Upvotes: 0

acdcjunior
acdcjunior

Reputation: 135812

Why?

...do you need to force an update?

Perhaps you are not exploring Vue at its best:

To have Vue automatically react to value changes, the objects must be initially declared in data. Or, if not, they must be added using Vue.set().

See comments in the demo below. Or open the same demo in a JSFiddle here.

new Vue({
  el: '#app',
  data: {
    person: {
      name: 'Edson'
    }
  },
  methods: {
    changeName() {
      // because name is declared in data, whenever it
      // changes, Vue automatically updates
      this.person.name = 'Arantes';
    },
    changeNickname() {
      // because nickname is NOT declared in data, when it
      // changes, Vue will NOT automatically update
      this.person.nickname = 'Pele';
      // although if anything else updates, this change will be seen
    },
    changeNicknameProperly() {
      // when some property is NOT INITIALLY declared in data, the correct way
      // to add it is using Vue.set or this.$set
      Vue.set(this.person, 'address', '123th avenue.');
      
      // subsequent changes can be done directly now and it will auto update
      this.person.address = '345th avenue.';
    }
  }
})
/* CSS just for the demo, it is not necessary at all! */
span:nth-of-type(1),button:nth-of-type(1) { color: blue; }
span:nth-of-type(2),button:nth-of-type(2) { color: red; }
span:nth-of-type(3),button:nth-of-type(3) { color: green; }
span { font-family: monospace }
<script src="https://unpkg.com/vue@2"></script>

<div id="app">
  <span>person.name: {{ person.name }}</span><br>
  <span>person.nickname: {{ person.nickname }}</span><br>
  <span>person.address: {{ person.address }}</span><br>
  <br>
  <button @click="changeName">this.person.name = 'Arantes'; (will auto update because `name` was in `data`)</button><br>
  <button @click="changeNickname">this.person.nickname = 'Pele'; (will NOT auto update because `nickname` was not in `data`)</button><br>
  <button @click="changeNicknameProperly">Vue.set(this.person, 'address', '99th st.'); (WILL auto update even though `address` was not in `data`)</button>
  <br>
  <br>
  For more info, read the comments in the code. Or check the docs on <b>Reactivity</b> (link below).
</div>

To master this part of Vue, check the Official Docs on Reactivity - Change Detection Caveats. It is a must read!

Upvotes: 63

Dec, 2021 Update:

You can force-reload components by adding :key="$route.fullPath".

For Child Component:

<Child :key="$route.fullPath" />

For router-view tag:

<router-view :key="$route.fullPath" />

However, :key="$route.fullPath" only can force-reload the components of the different route but not the components of the same route. To be able to force-reload the components of the same route as well, we need to add "value" with an array to :key="$route.fullPath" and change "value". So it becomes :key="[$route.fullPath, value]" and we need to change "value".

*We can assign Array to :key=.

<template>
  <Child 
    :key="[$route.fullPath, value]" // Can assign "Array" to ":key="
    @childReload="reload" // Call @click="$emit('childReload')" in   
  />                      // Child Component to increment the value.
</template> 

    OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR

<template>
  <router-view 
    :key="[$route.fullPath, value]" // Can assign "Array" to ":key="
    @routerViewReload="reload" // Call @click="$emit('routerViewReload')"
  />                           // in Child Component to increment the value.
</template>
    
<script>
export default {
  name: "Parent", components: { Child, },
  data() {
    return {
      value: 0,
    };
  },
  methods: {
    reload() {
      this.value++;
    }
  }
}
</script>

However, to keep using both "$route.fullPath" and "value" causes some error sometimes so only when some event like Click happens, we use both "$route.fullPath" and "value". Except when some event like Click happens, we always need to use only "$route.fullPath".

This is the final code:

<template>
  <Child 
    :key="state ? $route.fullPath : [$route.fullPath, value]"
    @childReload="reload" // Call @click="$emit('childReload')" in
  />                      // Child Component to increment the value.
</template>
    
    OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR
    
<template>
  <router-view 
    :key="state ? $route.fullPath : [$route.fullPath, value]"
    @routerViewReload="reload" // Call @click="$emit('routerViewReload')" in
  />                           // Child Component to increment the value.
</template>
        
<script>
export default {
  name: "Parent", components: { Child, },
  data() {
    return {
      state: true,
      value: 0,
    };
  },
  methods: {
    reload() {
      this.state = false;
      this.value++;
      this.$nextTick(() => this.state = true);
    }
  }
}
</script>

Unfortunately, there are no simple ways to force-reload components properly in Vue. That's the problem of Vue for now.

Upvotes: 7

Rai Ahmad Fraz
Rai Ahmad Fraz

Reputation: 41

<router-view :key="$route.params.slug" />

Just use key with your any params its auto reload children..

Upvotes: 4

mgoetzke
mgoetzke

Reputation: 832

Sure .. you can simply use the key attribute to force re-render (recreation) at any time.

<mycomponent :key="somevalueunderyourcontrol"></mycomponent>

See https://jsfiddle.net/mgoetzke/epqy1xgf/ for an example

It was also discussed here: https://github.com/vuejs/Discussion/issues/356#issuecomment-336060875

Upvotes: 26

Sandeep Rana
Sandeep Rana

Reputation: 309

If you are using router-view or Vue Router, you can directly use the key feature

<router-view :key="$route.path"></router-view>

This will tell the router view to re-render the page every time the path is changed.

Upvotes: 0

Geoff
Geoff

Reputation: 6649

Using v-if directive

<div v-if="trulyvalue">
  <component-here />
</div>

So simply by changing the value of trulyvalue from false to true will cause the component between the div to rerender again

Upvotes: 7

Felix Labayen
Felix Labayen

Reputation: 405

In order to reload/re-render/refresh component, stop the long codings. There is a Vue.JS way of doing that.

Just use :key attribute.

For example:

<my-component :key="unique" />

I am using that one in BS Vue Table Slot. Telling that I will do something for this component so make it unique.

Upvotes: 13

Shahrukh Anwar
Shahrukh Anwar

Reputation: 2632

So there's two way you can do this,

  1. You can use $forceUpdate() inside your method handler i.e

<your-component @click="reRender()"></your-component>

<script>
export default {
   methods: {
     reRender(){
        this.$forceUpdate()
     }
   }
}
</script>
  1. You can give a :key attribute to your component and increment when want to rerender

<your-component :key="index" @click="reRender()"></your-component>

<script>
export default {
   data() {
     return {
        index: 1
     }
   },
   methods: {
     reRender(){
        this.index++
     }
   }
}
</script>

Upvotes: 15

Pushkar Shirodkar
Pushkar Shirodkar

Reputation: 684

<my-component :key="uniqueKey" />

along with it use this.$set(obj,'obj_key',value) and update uniqueKey for every update in object (obj) value for every update this.uniqueKey++

it worked for me this way

Upvotes: 14

Yash
Yash

Reputation: 7064

Please read this http://michaelnthiessen.com/force-re-render/

The horrible way: reloading the entire page
The terrible way: using the v-if hack
The better way: using Vue’s built-in forceUpdate method
The best way: key-changing on your component

<template>
   <component-to-re-render :key="componentKey" />
</template>

<script>
 export default {
  data() {
    return {
      componentKey: 0,
    };
  },
  methods: {
    forceRerender() {
      this.componentKey += 1;  
    }
  }
 }
</script>

I also use watch: in some situations.

Upvotes: 142

this
this

Reputation: 96

If your URL changes as well when if the component is loaded you can just use it in the :key attribute. This works especially well if you use it on the router-view tag directly. And this commes with the added benedit of the key being a value that is actually tied to the content of the page instead of just some random number.

<router-view :key="this.$route.path"></router-view>

Upvotes: 0

denis.peplin
denis.peplin

Reputation: 9851

Use vm.$set('varName', value).

Look for details into Change_Detection_Caveats

Upvotes: 25

Boris Mossounov
Boris Mossounov

Reputation: 4122

Try this magic spell:

vm.$forceUpdate();
//or in file components
this.$forceUpdate();

No need to create any hanging vars :)

Update: I found this solution when I only started working with VueJS. However further exploration proved this approach as a crutch. As far as I recall, in a while I got rid of it simply putting all the properties that failed to refresh automatically (mostly nested ones) into computed properties.

More info here: https://v2.vuejs.org/v2/guide/computed.html

Upvotes: 368

Brad
Brad

Reputation: 840

For anyone still looking around, there's a package for this now.

https://github.com/gabrielmbmb/vuex-multi-tab-state

All I had to do was install it and add it to my plugins in main.ts (as it shows on that page) and it did exactly what I wanted.

Upvotes: 0

Rahman Rezaee
Rahman Rezaee

Reputation: 2165

Add this code:

this.$forceUpdate()

Upvotes: 1

sailfish009
sailfish009

Reputation: 2927

Except page reload method(flickering), none of them works for me (:key didn't worked).

and I found this method from old vue.js forum which is works for me:

https://github.com/vuejs/Discussion/issues/356

<template>
    <div v-if="show">
       <button @click="rerender">re-render</button>
    </div>
</template>
<script>
    export default {
        data(){
            return {show:true}
        },
        methods:{
            rerender(){
                this.show = false
                this.$nextTick(() => {
                    this.show = true
                    console.log('re-render start')
                    this.$nextTick(() => {
                        console.log('re-render end')
                    })
                })
            }
        }
    }
</script>

Upvotes: 1

sean717
sean717

Reputation: 12663

This has worked for me.

created() {
    EventBus.$on('refresh-stores-list', () => {
        this.$forceUpdate();
    });
},

The other component fires the refresh-stores-list event will cause the current component to rerender

Upvotes: 4

john-raymon
john-raymon

Reputation: 326

The approach of adding :key to the vue-router lib's router-view component cause's fickers for me, so I went vue-router's 'in-component guard' to intercept updates and refresh the entire page accordingly when there's an update of the path on the same route (as $router.go, $router.push, $router.replace weren't any help). The only caveat with this is that we're for a second breaking the singe-page app behavior, by refreshing the page.

  beforeRouteUpdate(to, from, next) {
    if (to.path !== from.path) {
      window.location = to.path;
    }
  },

Upvotes: 2

tuwilof
tuwilof

Reputation: 587

Worked for me

    data () {
        return {
            userInfo: null,
            offers: null
        }
    },

    watch: {
        '$route'() {
            this.userInfo = null
            this.offers = null
            this.loadUserInfo()
            this.getUserOffers()
        }
    }

Upvotes: 3

Poy Chang
Poy Chang

Reputation: 1156

Try to use this.$router.go(0); to manually reload the current page.

Upvotes: 72

Brian Kung
Brian Kung

Reputation: 4277

This seems like a pretty clean solution from matthiasg on this issue:

you can also use :key="someVariableUnderYourControl" and change the key when you want to component to be completely rebuilt

For my use case, I was feeding a Vuex getter into a component as a prop. Somehow Vuex would fetch the data but the reactivity wouldn't reliably kick in to rerender the component. In my case, setting the component key to some attribute on the prop guaranteed a refresh when the getters (and the attribute) finally resolved.

Upvotes: 160

Laszlo the Wiz
Laszlo the Wiz

Reputation: 574

I found a way. It's a bit hacky but works.

vm.$set("x",0);
vm.$delete("x");

Where vm is your view-model object, and x is a non-existent variable.

Vue.js will complain about this in the console log but it does trigger a refresh for all data. Tested with version 1.0.26.

Upvotes: 2

Related Questions