Pouvez-vous forcer Vue.js à recharger / re-rendre?

232

Juste une petite question.

Pouvez-vous forcer Vue.jsà tout recharger / recalculer ? Si c'est le cas, comment?

Dave
la source
Pourrait
Cory Danielson
Super, je ne connaissais pas ce lieu de discussion. Je vais essayer là-bas.
Dave
Avez-vous fini par obtenir une réponse? Je veux aussi savoir.
Oddman
Je ne me souviens pas exactement. Mais voici le problème que j'ai ouvert avec quelques indices: github.com/vuejs/Discussion/issues/356
Dave
J'ai la directive v-for dans la vue et j'ai un cas d'utilisation lorsque j'échange manuellement deux objets sur ce tableau. Vue ne redirige pas automatiquement le modèle après cela. J'ai utilisé une solution de contournement: effectuez n'importe quelle action avec ce tableau (appuyez sur un objet vide, puis épissez) - cela déclenche un nouveau rendu. Mais c'est un cas particulier.
Fyodor Khruschov

Réponses:

237

Essayez ce sort magique:

vm.$forceUpdate();

Pas besoin de créer de vars suspendus :)

Mettre à jour: j'ai trouvé cette solution lorsque j'ai seulement commencé à travailler avec VueJS. Cependant, une exploration plus approfondie a prouvé cette approche comme une béquille. Pour autant que je me souvienne, dans un certain temps, je m'en suis débarrassé en mettant simplement toutes les propriétés qui n'ont pas pu être actualisées automatiquement (la plupart imbriquées) dans des propriétés calculées.

Plus d'informations ici: https://vuejs.org/v2/guide/computed.html

Boris Mossounov
la source
4
cela m'a vraiment aidé lorsque je l'utilisais avec un composant d'assistant de formulaire dans Vue. Mes champs de champs de formulaire perdaient leur état bien que les variables de données soient intactes. Maintenant, je l'utilise pour rafraîchir les vues quand je reviens, je devais le placer dans la fonction setTimeout.
Jimmy Ilenloa
26
Notez que dans les fichiers vue, vous avez besoin de 'this. $ ForceUpdate ();'
Katinka Hesselink
1
Cela fonctionne très bien pour mettre à jour un après un long appel axios.
AlfredBr
4
D'une manière absolument bizarre, $forceUpdate()je n'ai JAMAIS travaillé pour moi sur 2.5.17.
Abana Clara
2
@AbanaClara $ forceUpdate () n'a jamais été une méthode publique, je l'ai trouvée en creusant le code source de Vue. Et comme son utilisation n'a jamais été la bonne façon de voir, cela pourrait peut-être être supprimé. Je ne peux pas dire avec certitude s'il est toujours là, car je ne fais plus de front-end.
Boris Mossounov
82

Cela semble être une solution assez propre de matthiasg sur ce problème :

vous pouvez également utiliser :key="someVariableUnderYourControl"et modifier la clé lorsque vous souhaitez que le composant soit complètement reconstruit

Pour mon cas d'utilisation, j'alimentais un getter Vuex dans un composant comme accessoire. D'une manière ou d'une autre, Vuex récupérait les données, mais la réactivité ne se déclenchait pas de manière fiable pour restituer le composant. Dans mon cas, définir le composant keysur un attribut sur l'hélice garantissait un rafraîchissement lorsque les getters (et l'attribut) se seraient finalement résolus.

Brian Kung
la source
1
C'est une petite astuce intéressante, elle force essentiellement une ré-instanciation du composant ( mountedsera exécutée, etc.)
btk
1
@btk Je suis d'accord, ce n'est probablement pas la "bonne" façon de faire les choses, mais c'est un hack assez propre, pour ce que c'est.
Brian Kung
1
c'est utile. J'utilise le chemin complet de l'itinéraire comme clé pour rendre à nouveau le même composant lorsque l'itinéraire change. : key = "$ route.fullPath"
Nirav Gandhi
44

Pourquoi?

... avez-vous besoin de forcer une mise à jour?

Peut-être que vous n'explorez pas Vue à son meilleur:

Pour que Vue réagisse automatiquement aux changements de valeur, les objets doivent être initialement déclarés dansdata . Sinon, ils doivent être ajoutés à l'aide deVue.set() .

Voir les commentaires dans la démo ci-dessous. Ou ouvrez la même démo dans un JSFiddle ici .

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>

Pour maîtriser cette partie de Vue, consultez les documents officiels sur la réactivité - mises en garde concernant la détection des changements . C'est à lire absolument!

acdcjunior
la source
2
Je suis tout à fait d'accord pour que vous remettiez en question cette exigence de rafraîchissement, mais parfois vous avez juste besoin de l'interface utilisateur pour effectuer un nouveau rendu car la fenêtre a changé et vous devez afficher différents actifs (comme un exemple). Les données n'ont peut-être pas réellement changé.
the_dude_abides
1
Pourquoi avez-vous besoin de recharger? Dans certains cas, les fichiers de ressources (feuilles de style / js) mis en cache par le navigateur doivent être rechargés après un certain laps de temps. J'avais une feuille de style qui devait être rechargée après 7 jours et si un utilisateur gardait un onglet ouvert avec un accès à la page et revenait après 7 jours pour parcourir cette page, le css avait plus de 7 jours.
Aurovrata
@AchielVolckaert vous avez probablement déjà trouvé la réponse, mais oui, Vue.set()fonctionne également à l'intérieur des composants.
acdcjunior
1
@the_dude_abides et @ Aurovrata, ce sont des utilisations légitimes de rafraîchissement, je suis d'accord. La question que j'ai posée est que les gens ne font pas rarement le rafraîchissement pour de mauvaises raisons.
acdcjunior
1
Peut-être que vous essayez simplement de corriger un bogue dans une application Web mal conçue qui utilise vue uniquement comme un outil de rendu, et par exemple recharge toute l'application chaque fois qu'elle va sur le serveur, ignorant les capacités d'application côté client de vue. Dans le monde réel, vous n'avez pas toujours le temps de réparer toutes les abominations que vous trouvez.
Warren Dew
30

Veuillez lire ce http://michaelnthiessen.com/force-re-render/

L'horrible façon: recharger la page entière
L'horrible façon: utiliser le hack v-if
La meilleure façon: utiliser la méthode forceUpdate intégrée de Vue
La meilleure façon: changer la clé de votre composant

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

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

J'utilise également la montre: dans certaines situations.

Yash
la source
Absolument, je suis d'accord avec toi!
Diamond
J'ai presque abandonné Vue. Mais grâce à cela, ma foi en Vue a été rétablie.
jokab
Le lien ne montre pas vraiment comment le faire de manière horrible, ce qui est malheureusement ce dont j'ai besoin car mon application est conçue pour naviguer de manière horrible. Une simple URL vers la page actuelle ne semble pas fonctionner, du moins pas dans l'application avec laquelle j'ai affaire, j'ai donc besoin d'instructions sur la façon de le faire de manière horrible.
Warren Dew
@WarrenDew Veuillez suivre: stackoverflow.com/questions/3715047/…
Yash
25

Essayez d'utiliser this.$router.go(0);pour recharger manuellement la page actuelle.

Poy Chang
la source
3
Plus simple: ceci. $ Router.go ()
Marius
En fait @MariusAndreiana - la fonction .go () nécessite 1 paramètre non optionnel
a_lovelace
23

Utilisez vm.$set('varName', value). Recherchez les détails dans Change_Detection_Caveats .

denis.peplin
la source
12
<my-component :key="uniqueKey" />

avec elle utiliser this.$set(obj,'obj_key',value) et mettre uniqueKeyà jour pour chaque mise à jour dans la valeur d'objet (obj) pour chaque mise à jourthis.uniqueKey++

cela a fonctionné pour moi de cette façon

Pushkar Shirodkar
la source
6

Il y a donc deux façons de le faire,

1). Vous pouvez utiliser à l' $forceUpdate()intérieur de votre gestionnaire de méthode ie

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

<script>
export default {
   methods: {
     reRender(){
        this.$forceUpdate()
     }
   }
}
</script>

2). Vous pouvez attribuer un :keyattribut à votre composant et incrémenter lorsque vous souhaitez effectuer un nouveau rendu

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

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

en utilisant la directive v-if

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

Donc, simplement en changeant la valeur de truevalue de false en true, le composant entre le div sera à nouveau rendu

Geoff
la source
1
À mon avis, c'est le moyen le plus propre de recharger le composant. Altough dans la méthode created () Vous pouvez ajouter des éléments d'initialisation.
Piotr Żak
5

Afin de recharger / re-rendre / rafraîchir le composant, arrêtez les longs codages. Il y a une façon Vue.JS de le faire.

Utilisez simplement l' :keyattribut.

Par exemple:

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

J'utilise celui-ci dans la fente de table BS Vue. Dire que je ferai quelque chose pour ce composant, alors rendez-le unique.

Felix Labayen
la source
3

Cela a fonctionné pour moi.

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

L'autre composant déclenche l'événement refresh-stores-list provoquera le nouveau rendu du composant actuel

sean717
la source
2

J'ai trouvé un moyen. C'est un peu hacky mais ça marche.

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

Où se vmtrouve votre objet de modèle de vue et xest une variable inexistante.

Vue.js s'en plaindra dans le journal de la console mais cela déclenchera une actualisation de toutes les données. Testé avec la version 1.0.26.

Laszlo le Wiz
la source
2

Travaillé pour moi

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

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

ajoutez simplement ce code:

this.$forceUpdate()

Bonne chance

RahmanRezaee
la source
0

: key = "$ route.params.param1" utilisez simplement la clé avec tous vos paramètres ses enfants de rechargement automatique ..

Rai Ahmad Fraz
la source
4
essayez de donner des informations détaillées sur votre solution. ajoutez votre code, mettez en surbrillance les mots
Agilanbu
0

J'ai eu ce problème avec une galerie d'images que je voulais rendre en raison de modifications apportées sur un autre onglet. Donc tab1 = imageGallery, tab2 = favoriteImages

tab @ change = "updateGallery ()" -> cela force ma directive v-for à traiter la fonction filterImages chaque fois que je change d'onglet.

<script>
export default {
  data() {
    return {
      currentTab: 0,
      tab: null,
      colorFilter: "",
      colors: ["None", "Beige", "Black"], 
      items: ["Image Gallery", "Favorite Images"]
    };
  },
  methods: {
    filteredImages: function() {
      return this.$store.getters.getImageDatabase.filter(img => {
        if (img.color.match(this.colorFilter)) return true;
      });
    },
    updateGallery: async function() {
      // instance is responsive to changes
      // change is made and forces filteredImages to do its thing
      // async await forces the browser to slow down and allows changes to take effect
      await this.$nextTick(function() {
        this.colorFilter = "Black";
      });

      await this.$nextTick(function() {
        // Doesnt hurt to zero out filters on change
        this.colorFilter = "";
      });
    }
  }
};
</script>
Jason
la source
0

désolé les gars, sauf la méthode de rechargement des pages (scintillement), aucune ne fonctionne pour moi (: la clé n'a pas fonctionné).

et j'ai trouvé cette méthode sur l'ancien forum vue.js qui fonctionne pour moi:

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>
sailfish009
la source