396

Just a quick question.

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

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Dave
  • 12,117
  • 10
  • 46
  • 52

22 Answers22

360

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

tony19
  • 125,647
  • 18
  • 229
  • 307
Boris Mossounov
  • 4,032
  • 2
  • 15
  • 11
  • 6
    this really helped me when I was using it with a form wizard component in Vue. My form fields fields were loosing state though the data variables were intact. Now I am using this to refresh the views when I go back, I had to place it in setTimeout function. – Jimmy Ilenloa Aug 18 '17 at 18:13
  • 66
    Note that in vue files you need 'this.$forceUpdate();' – Katinka Hesselink Jan 03 '19 at 09:07
  • 20
    In some absolutely weird way `$forceUpdate()` never EVER worked for me on 2.5.17. – Abana Clara Feb 25 '19 at 07:30
  • 4
    @AbanaClara $forceUpdate() never was a public method, I found it digging source code of Vue. And since it's usage never was the right way of Vue'ing, perhaps it could be stripped out. Cannot say for sure if it is still there, since I don't do front-end anymore. – Boris Mossounov Feb 26 '19 at 12:29
  • This does not help if you need to actually re-trigger the route, and it's guards. Lets say that your route fetches data, and inserts it into component props. Without reloading the entire page, how do you get vue router to refresh the route? – Douglas Gaskell Aug 13 '20 at 23:57
  • Computed properties worked for me but I had to add to define the whole object as computed in cases where it was an object with multiple nested value where some might be updated based on state. (i.e options object of a video player) – csalmeida May 31 '21 at 20:33
  • Do you have to do that with later versions of vue.js as well? – Anders Lindén Jun 09 '21 at 11:12
  • Just use Snabbdom on which Vue was based at the first place. Simply traverse the whole VDOM pure-functional hierarchy on any change you get. It's super fast if you don't have to compute state of a giant IDE/EDA/CAD on every state change. – Brian Cannard Feb 25 '22 at 05:32
144

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.

Brian Kung
  • 3,957
  • 4
  • 21
  • 30
  • 4
    This is a neat little trick, it basically forces a re-instantiation of the component (`mounted` will be run, etc) – btk Oct 22 '18 at 19:32
  • 1
    @btk I agree, it's probably not the "right' way to do things, but it is a fairly clean hack, for what it is. – Brian Kung Oct 23 '18 at 03:47
  • 3
    this helpful. I use route full path as the key to rerender the same component when the route changes. :key="$route.fullPath" – Nirav Gandhi Jan 07 '19 at 09:26
  • I just came up with a pro hack: `:key="'pro-hack-'+arr.length"`, causes it to refresh when a new item is added/removed from the array. I had a warzone condition where the slot content was not updating only when the component was currently scrolled max-right – agm1984 Feb 16 '23 at 21:08
127

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.

kissu
  • 40,416
  • 14
  • 65
  • 133
Yash
  • 6,644
  • 4
  • 36
  • 26
  • The link doesn't actually show how to do it the horrible way, which is unfortunately what I need since my app is designed around navigating the horrible way. A simple URL to the current page doesn't seem to work, at least not in the app I'm dealing with, so I actually need instructions on how to do it the horrible way. – Warren Dew Dec 09 '19 at 04:53
  • @WarrenDew Please follow: https://stackoverflow.com/questions/3715047/how-to-reload-a-page-using-javascript – Yash Jan 18 '20 at 02:08
  • I like the horrible way. Put this line in a watcher window.location.reload(); – Cao Shouguang Feb 21 '23 at 17:19
68

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

Poy Chang
  • 1,106
  • 1
  • 10
  • 13
66

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"></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!

tony19
  • 125,647
  • 18
  • 229
  • 307
acdcjunior
  • 132,397
  • 37
  • 331
  • 304
  • 2
    Definitely agree that you should question this refresh requirement, but sometimes you just need the UI to re-render because the viewport has changed and you need to show different assets (as one example). The data may not have actually changed. – the_dude_abides Aug 28 '18 at 23:20
  • 1
    Why do you need to reload? In some cases resource files (stylesheets/js) cached by the browser need to be reloaded after a certain period of time. I had a stylesheet that needed to be reloaded after 7 days and if a user kept a tab open with a page access and came back after 7 days to navigate that page, the css was more than 7 days old. – Aurovrata Nov 27 '18 at 10:43
  • 1
    @AchielVolckaert you probably have already found the answer, but yes, `Vue.set()` also works inside components. – acdcjunior Mar 22 '19 at 21:44
  • 2
    @the_dude_abides and @ Aurovrata, those are legitimate uses of refreshing, I agree. The questioning I posed is that people not rarely do the refreshing for the wrong reasons. – acdcjunior Mar 22 '19 at 21:45
  • 1
    Perhaps you're just trying to fix a bug in a poorly designed web app that uses vue purely as a rendering tool, and for example reloads the entire application whenever it goes to the server, ignoring the client side application capabilities of vue. In the real world, you don't always have the time to fix every abomination you find. – Warren Dew Dec 09 '19 at 04:48
  • There are situations that require a forced update. Example: an image component that points to the URL of the picture of the user profile. In the same page the user can submit a new picture and the image component should re-render to get the updated data. In this case, the URL of the image component does not change for the same user (i.e.: /images/profile/john-avatar.jpg). – Alexandre V. Feb 09 '20 at 10:57
  • Why do you need to reload? Switching translations <- because they are not driven by your data. They are a mess you do not want to muddy your scope, nor want it to maintain. – Daniel ZA May 01 '20 at 11:11
  • > Why? I'm trying to re-render a pure-functional components tree which destructures and maps a complex tree hierarchy passed from the root App component. Attempting to change one field doesn't trigger automatic re-render. Array elements and Object properties are added and removed in event handler and network response handlers, and I absolutely don't want to traverse the entire tree and tell Vue's reactive system imperatively what was added and removed. What's the point of reactivity at the first place then?.. – Brian Cannard Feb 25 '22 at 04:49
25

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

Look for details into Change_Detection_Caveats

kissu
  • 40,416
  • 14
  • 65
  • 133
denis.peplin
  • 9,585
  • 3
  • 48
  • 55
25

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

kissu
  • 40,416
  • 14
  • 65
  • 133
mgoetzke
  • 804
  • 7
  • 14
15

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>
kissu
  • 40,416
  • 14
  • 65
  • 133
Shahrukh Anwar
  • 2,544
  • 1
  • 24
  • 24
14
<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

kissu
  • 40,416
  • 14
  • 65
  • 133
13

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.

kissu
  • 40,416
  • 14
  • 65
  • 133
Felix Labayen
  • 385
  • 3
  • 8
7

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.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
6

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

kissu
  • 40,416
  • 14
  • 65
  • 133
Geoff
  • 6,277
  • 23
  • 87
  • 197
  • 1
    In my opinion this is cleanest way to reload component. Altough in created() method You can add some initialization stuff. – Piotr Żak Oct 07 '18 at 15:32
4

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

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
sean717
  • 11,759
  • 20
  • 66
  • 90
4
<router-view :key="$route.params.slug" />

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

kissu
  • 40,416
  • 14
  • 65
  • 133
  • 8
    try to give a detailed information about your solution. add your code ,highlight the keywords – Agilanbu Apr 22 '19 at 09:43
  • Thanks, this worked for me. Handy when using sub-routes and you want to reload the content based on different routes. – Jack Barham Nov 18 '21 at 09:42
3

Worked for me

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

    watch: {
        '$route'() {
            this.userInfo = null
            this.offers = null
            this.loadUserInfo()
            this.getUserOffers()
        }
    }
tuwilof
  • 351
  • 3
  • 6
  • This is the way, I was facing similar issue with a paginated view using tags to filter the query, and navigating through tags didn't refresh the component albeit using :key=tag.id – d70rr3s Apr 14 '23 at 21:09
2

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.

Laszlo the Wiz
  • 554
  • 4
  • 14
2

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;
    }
  },
john-raymon
  • 306
  • 1
  • 7
  • 20
1

Add this code:

this.$forceUpdate()
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Rahman Rezaee
  • 1,943
  • 16
  • 24
  • This does not work if you need the actual route to re-trigger, which triggers data fetching in your route guards to fetch data for component properties that vue-router inserts. – Douglas Gaskell Aug 13 '20 at 23:56
  • I use Quasar and it has Vue-Router as a nailed hardcoded dependency. Is that what not letting `$forceUpdate()` do its work?... – Brian Cannard Feb 25 '22 at 04:43
1

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>
Nimantha
  • 6,405
  • 6
  • 28
  • 69
sailfish009
  • 2,561
  • 1
  • 24
  • 31
0

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.

Brad
  • 722
  • 2
  • 8
  • 24
0

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>
this
  • 94
  • 1
  • 6
0

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.

Sandeep Rana
  • 179
  • 2
  • 6