Existe uma maneira adequada de redefinir os dados iniciais de um componente em vuejs?

97

Eu tenho um componente com um conjunto específico de dados iniciais:

data: function (){
    return {
        modalBodyDisplay: 'getUserInput', // possible values: 'getUserInput', 'confirmGeocodedValue'
        submitButtonText: 'Lookup', // possible values 'Lookup', 'Yes'
        addressToConfirm: null,
        bestViewedByTheseBounds: null,
        location:{
            name: null,
            address: null,
            position: null
        }
}

Esses são os dados de uma janela modal, então, quando aparecer, quero que comece com esses dados. Se o usuário cancelar a janela, desejo redefinir todos os dados para isso.

Sei que posso criar um método para redefinir os dados e apenas definir manualmente todas as propriedades dos dados de volta ao original:

reset: function (){
    this.modalBodyDisplay = 'getUserInput';
    this.submitButtonText = 'Lookup';
    this.addressToConfirm = null;
    this.bestViewedByTheseBounds = null;
    this.location = {
        name: null,
        address: null,
        position: null
    };
}

Mas isso parece muito desleixado. Isso significa que, se eu fizer alguma alteração nas propriedades de dados do componente, vou precisar ter certeza de que me lembrarei de atualizar a estrutura do método de redefinição. Isso não é absolutamente horrível, já que é um pequeno componente modular, mas faz a parte de otimização do meu cérebro gritar.

A solução que eu pensei que funcionaria seria pegar as propriedades dos dados iniciais em um readymétodo e usar esses dados salvos para redefinir os componentes:

data: function (){
    return {
        modalBodyDisplay: 'getUserInput', 
        submitButtonText: 'Lookup', 
        addressToConfirm: null,
        bestViewedByTheseBounds: null,
        location:{
            name: null,
            address: null,
            position: null
        },
        // new property for holding the initial component configuration
        initialDataConfiguration: null
    }
},
ready: function (){
    // grabbing this here so that we can reset the data when we close the window.
    this.initialDataConfiguration = this.$data;
},
methods:{
    resetWindow: function (){
        // set the data for the component back to the original configuration
        this.$data = this.initialDataConfiguration;
    }
}

Mas o initialDataConfigurationobjeto está mudando junto com os dados (o que faz sentido porque no método read, estamos initialDataConfigurationobtendo o escopo da função de dados.

Existe uma maneira de obter os dados de configuração inicial sem herdar o escopo?

Estou pensando demais nisso e há uma maneira melhor / mais fácil de fazer isso?

Codificar os dados iniciais é a única opção?

Chris Schmitz
fonte
Você está usando v-show ou v-if para exibir o modal?
Rwd
Estou usando o bootstrap para o css, então estou usando o modal integrado que aproveita o jquery para mostrar e ocultar. Basicamente, a parte da janela do componente está sempre lá, apenas oculta.
Chris Schmitz

Respostas:

128
  1. extrair os dados iniciais em uma função fora do componente
  2. use essa função para definir os dados iniciais no componente
  3. reutilize essa função para redefinir o estado quando necessário.

// outside of the component:
function initialState (){
  return {
    modalBodyDisplay: 'getUserInput', 
    submitButtonText: 'Lookup', 
    addressToConfirm: null,
    bestViewedByTheseBounds: null,
    location:{
      name: null,
      address: null,
      position: null
    }
  }
}

//inside of the component:
data: function (){
    return initialState();
} 


methods:{
    resetWindow: function (){
        Object.assign(this.$data, initialState());
    }
}

Linus Borg
fonte
5
Isso foi o suficiente. Obrigado! Fiz uma pequena edição na resposta, mas apenas porque um componente vue requer uma função retornada para dados em vez de apenas um objeto. Seu conceito de respostas definitivamente funciona e está correto, a edição é apenas para explicar como o vuejs lida com os componentes.
Chris Schmitz
3
Você está certo sobre a função da propriedade de dados, que fui descuidado. Obrigado pela edição.
Linus Borg
13
Agora dá um erro:[Vue warn]: Avoid replacing instance root $data. Use nested data properties instead.
Sankalp Singha
34
@SankalpSingha Vue 2.0 não permite mais que você faça isso. Você pode usar em seu Object.assignlugar. Aqui está o código de trabalho: codepen.io/CodinCat/pen/ameraP?editors=1010
CodinCat
3
Para este problema - [Vue warn]: Evite substituir a raiz $ data da instância. Use propriedades de dados aninhados, tente isso. $ Data.propName = "new value";
Stanislav Ostapenko
35

Para redefinir o componente dataem uma instância de componente atual, você pode tentar isto:

Object.assign(this.$data, this.$options.data())

Particularmente, tenho um componente modal abstrato que utiliza slots para preencher várias partes do diálogo. Quando o modal personalizado envolve esse modal abstrato, os dados referidos nos slots pertencem ao escopo do componente pai . Aqui está a opção do modal abstrato que redefine os dados toda vez que o modal personalizado é mostrado (código ES2015):

watch: {
    show (value) { // this is prop's watch
      if(value) {
        Object.assign(this.$parent.$data, this.$parent.$options.data())
      }
    }
}

Você pode ajustar sua implementação modal, é claro - acima também pode ser executado em algum cancelgancho.

Tenha em mente que a mutação das $parentopções do filho não é recomendada, no entanto, acho que pode ser justificado se o componente pai estiver apenas personalizando o modal abstrato e nada mais.

Gertas
fonte
1
Essa técnica agora fornece um aviso VueJS; consulte stackoverflow.com/questions/40340561/…
Kivi Shapiro
7
Cuidado, isso não vincula o contexto a data. Portanto, se você estiver usando thisem seu datamétodo, pode aplicar o contexto com:Object.assign(this.$data, this.$options.data.apply(this))
Se não
Qual é a vantagem dessa forma em relação a location.reload ()?
Carlos
33

Cuidado, Object.assign(this.$data, this.$options.data())não vincula o contexto a data ().

Então use isto:

Object.assign(this.$data, this.$options.data.apply(this))

cc esta resposta estava originalmente aqui

Roli Roli
fonte
6

Se você está incomodado com os avisos, este é um método diferente:

const initialData = () => ({})

export default {
  data() {
    return initialData();
  },
  methods: {
    resetData(){
      const data = initialData()
      Object.keys(data).forEach(k => this[k] = data[k])
    }
  }
}

Não há necessidade de mexer com $ data.

srmico
fonte
2

Tive que redefinir os dados para o estado original dentro de um componente filho, isto é o que funcionou para mim:

Componente pai, chamando o método do componente filho:

     <button @click="$refs.childComponent.clearAllData()">Clear All</button >

     <child-component ref='childComponent></child-component>

Componente filho:

  1. definir dados em uma função externa,
  2. atribuir o objeto de dados a uma função externa
  3. definindo o método clearallData () que deve ser chamado pelo componente pai

    function initialState() {
       return { 
         someDataParameters : '',
         someMoreDataParameters: ''
              }
      }
    
    export default {
       data() {
        return initialState();
      },
        methods: {
      clearAllData() {
      Object.assign(this.$data, initialState());
    },
    
Armin
fonte