Você pode forçar o Vue.js a recarregar / renderizar novamente?

231

Apenas uma pergunta rápida.

Você pode forçar Vue.jsa recarregar / recalcular tudo? Se sim, como?

Dave
fonte
Pode obter um melhor apoio aqui github.com/vuejs/Discussion/issues
Cory Danielson
Ótimo, não sabia sobre esse lugar de discussão. Vou tentar por lá.
Dave
Você acabou recebendo uma resposta? Estou ansioso para saber também.
Oddman
Não me lembro exatamente. Mas aqui está o problema que começou com algumas pistas: github.com/vuejs/Discussion/issues/356
Dave
Eu tenho a diretiva v-for na exibição e tenho caso de uso quando troco manualmente dois objetos nessa matriz. O Vue não renderiza automaticamente o modelo novamente depois disso. Eu usei a solução alternativa: basta executar qualquer ação com essa matriz (empurre o objeto vazio e depois emendar) - isso dispara a repetição. Mas este é um caso especial.
Fyodor Khruschov

Respostas:

237

Tente este feitiço mágico:

vm.$forceUpdate();

Não há necessidade de criar vars suspensos :)

Atualização: Encontrei esta solução quando comecei a trabalhar apenas com o VueJS. Contudo, novas explorações provaram essa abordagem como uma muleta. Tanto quanto me lembro, em pouco tempo me livrei dele, simplesmente colocando todas as propriedades que não eram atualizadas automaticamente (principalmente as aninhadas) nas propriedades calculadas.

Mais informações aqui: https://vuejs.org/v2/guide/computed.html

Boris Mossounov
fonte
4
isso realmente me ajudou quando eu o estava usando com um componente de assistente de formulário no Vue. Os campos dos meus campos de formulário estavam perdendo o estado, embora as variáveis ​​de dados estivessem intactas. Agora, estou usando isso para atualizar as visualizações quando voltar, tive que colocá-lo na função setTimeout.
Jimmy Ilenloa 18/08/19
26
Observe que nos arquivos vue você precisa 'this. $ ForceUpdate ();'
Katinka Hesselink
1
Isso funciona muito bem para atualizar uma chamada após axios longa.
AlfredBr
4
De uma maneira absolutamente estranha, $forceUpdate()NUNCA funcionou para mim na versão 2.5.17.
Abana Clara
2
@AbanaClara $ forceUpdate () nunca foi um método público, achei que ele estava procurando o código fonte do Vue. E como seu uso nunca foi o caminho certo de Vue'ing, talvez pudesse ser retirado. Não posso dizer com certeza se ele ainda está lá, pois eu não faço mais o front-end.
Boris Mossounov
82

Parece uma solução bastante limpa da matthiasg sobre esse problema :

você também pode usar :key="someVariableUnderYourControl"e alterar a chave quando desejar que o componente seja completamente reconstruído

Para o meu caso de uso, eu estava inserindo um getter Vuex em um componente como suporte. De alguma forma, o Vuex buscava os dados, mas a reatividade não era confiável para renderizar novamente o componente. No meu caso, definir o componente keypara algum atributo no suporte garantiu uma atualização quando os getters (e o atributo) finalmente foram resolvidos.

Brian Kung
fonte
1
Este é um truque pequeno puro, que basicamente obriga a re-instanciação do componente ( mountedserá executado, etc)
btk
1
@btk Concordo, não é provavelmente a maneira "certa' de fazer as coisas, mas é um hack bastante limpo, para o que é.
Brian Kung
1
isso é útil. Eu uso o caminho completo da rota como a chave para renderizar novamente o mesmo componente quando a rota é alterada. : key = "$ route.fullPath"
Gandhi
44

Por quê?

... você precisa forçar uma atualização?

Talvez você não esteja explorando o Vue da melhor maneira possível:

Para que o Vue reaja automaticamente às alterações de valor, os objetos devem ser declarados inicialmente emdata . Ou, se não, eles devem ser adicionados usandoVue.set() .

Veja os comentários na demonstração abaixo. Ou abra a mesma demonstração em um JSFiddle aqui .

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>

Para dominar esta parte do Vue, verifique os Documentos oficiais sobre reatividade - advertências de detecção de alterações . É uma leitura obrigatória!

acdcjunior
fonte
2
Concordo definitivamente que você deve questionar esse requisito de atualização, mas, às vezes, é necessário renderizar novamente a interface do usuário porque a viewport mudou e você precisa mostrar ativos diferentes (como um exemplo). Os dados podem não ter sido realmente alterados.
the_dude_abides 28/08
1
Por que você precisa recarregar? Em alguns casos, os arquivos de recursos (folhas de estilo / js) armazenados em cache pelo navegador precisam ser recarregados após um certo período de tempo. Eu tinha uma folha de estilo que precisava ser recarregada após 7 dias e se um usuário mantivesse uma guia aberta com um acesso à página e voltasse após 7 dias para navegar nessa página, o css tinha mais de 7 dias.
Aurovrata
@AchielVolckaert você provavelmente já encontrou a resposta, mas sim, Vue.set()também funciona dentro de componentes.
acdcjunior
1
@the_dude_abides e @ Aurovrata, esses são usos legítimos de atualização, eu concordo. O questionamento que propus é que as pessoas raramente fazem a atualização pelas razões erradas.
Acdcjunior 22/03/19
1
Talvez você esteja apenas tentando corrigir um bug em um aplicativo Web mal projetado que usa o vue puramente como uma ferramenta de renderização e, por exemplo, recarrega o aplicativo inteiro sempre que acessa o servidor, ignorando os recursos de aplicativo do cliente do vue. No mundo real, você nem sempre tem tempo para consertar todas as abominações que encontrar.
Warren Dew
30

Por favor, leia este http://michaelnthiessen.com/force-re-render/

A maneira horrível: recarregar a página inteira
A maneira terrível: usar o v-if hack
A melhor maneira: usar o método forceUpdate interno do Vue
A melhor maneira: alterar as chaves no seu componente

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

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

Eu também uso o watch: em algumas situações.

Yash
fonte
Absolutamente, eu concordo com você!
Diamante
Eu quase desisti de Vue. Mas, graças a isso, minha fé em Vue foi restaurada.
Jokab #
Na verdade, o link não mostra como fazê-lo da maneira horrível, o que infelizmente é o que eu preciso, pois meu aplicativo foi projetado para navegar da maneira horrível. Um URL simples para a página atual parece não funcionar, pelo menos não no aplicativo com o qual estou lidando, então, na verdade, preciso de instruções sobre como fazê-lo da maneira horrível.
Warren Orvalho
25

Tente usar this.$router.go(0);para recarregar manualmente a página atual.

Poy Chang
fonte
3
Mais simples: esse. $ Router.go ()
Marius
Na verdade @MariusAndreiana - o .go () função requer um parâmetro não opcional
a_lovelace
23

Use vm.$set('varName', value). Procure detalhes em Change_Detection_Caveats .

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

juntamente com ele use this.$set(obj,'obj_key',value) e atualize uniqueKeypara cada atualização no valor do objeto (obj) para cada atualizaçãothis.uniqueKey++

funcionou para mim dessa maneira

Pushkar Shirodkar
fonte
6

Portanto, há duas maneiras de fazer isso,

1) Você pode usar $forceUpdate()dentro de seu manipulador de métodos, ou seja,

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

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

2) Você pode atribuir um :keyatributo ao seu componente e aumentar quando desejar renderizar novamente

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

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

usando a diretiva v-if

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

Portanto, simplesmente alterando o valor de truevalue de false para true fará com que o componente entre a div seja renderizado novamente

Geoff
fonte
1
Na minha opinião, esta é a maneira mais limpa de recarregar o componente. Embora no método created () Você pode adicionar alguns itens de inicialização.
Piotr Żak
5

Para recarregar / renderizar novamente / atualizar o componente, pare as codificações longas. Existe uma maneira do Vue.JS de fazer isso.

Basta usar o :keyatributo

Por exemplo:

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

Estou usando esse no BS Vue Table Slot. Dizendo que farei algo para esse componente, torne-o único.

Felix Labayen
fonte
3

Isso tem funcionado para mim.

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

O outro componente dispara o evento refresh-stores-list fará com que o componente atual seja renderizado novamente

sean717
fonte
2

Eu encontrei um caminho. É um pouco hacky, mas funciona.

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

Onde vmestá o seu objeto de modelo de exibição e xé uma variável inexistente.

O Vue.js irá reclamar disso no log do console, mas disparará uma atualização para todos os dados. Testado com a versão 1.0.26.

Laszlo, o Wiz
fonte
2

Trabalhou para mim

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

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

basta adicionar este código:

this.$forceUpdate()

Boa sorte

RahmanRezaee
fonte
0

: key = "$ route.params.param1" basta usar a tecla com seus parâmetros para recarregar automaticamente os filhos.

Rai Ahmad Fraz
fonte
4
tente fornecer informações detalhadas sobre sua solução. adicione seu código, destaque as palavras
Agilanbu 22/04/19
0

Eu tive esse problema com uma galeria de imagens que queria renderizar novamente devido a alterações feitas em uma guia diferente. Então tab1 = imageGallery, tab2 = favoriteImages

tab @ change = "updateGallery ()" -> isso força minha diretiva v-for a processar a funçãofilImagesImages toda vez que alterno as guias.

<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
fonte
0

desculpe pessoal, exceto pelo método de recarregamento da página (tremulação), nenhum deles funciona para mim (: key não funcionou).

e eu encontrei esse método no antigo fórum vue.js, que funciona para mim:

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
fonte