Forza l'aggiornamento degli oggetti di scena nel componente figlio dopo l'aggiornamento di Vuex

Aug 21 2020

Ho un componente figlio ( <BaseProjectTable>) che viene riutilizzato in tutto il mio sito che contiene un <v-data-table>componente Vuetify . Le intestazioni e gli elementi di contenuto per la tabella dati vengono passati al componente come oggetti di scena ei dati dell'elemento vengono mappati nel genitore come mapGetterda un negozio Vuex. Il componente figlio contiene funzionalità di modifica per ogni riga e sto usando a mapActionper aggiornare i dati API e Vuex da lì, con l'idea che poiché il mio mapGetter è reattivo, dovrebbe aggiornare i dati e quindi la visualizzazione della tabella dei dati. Tuttavia, questo non funziona; Posso vedere tramite gli strumenti di sviluppo che lo stato viene aggiornato correttamente, ma la visualizzazione del componente figlio non lo è.

Ecco la parte rilevante del <BaseProjectTable>componente figlio :

<template>
  <div>
    <v-data-table
      show-expand
      :headers="headers"
      :items="filteredItems"
      :search="search"
      tem-key="sow"
      @click:row="rowClick"
      :hide-default-footer="disablePagination"
      dense
      :disable-pagination="disablePagination"
    >
    ...
    </v-data-table>

    ...
    export default {
    name: "BaseProjectTable",
    props: {
      headers: Array,
      items: Array,
      loggedInUser: Object,
      title: String,
      max2chars: v => v.length <= 2 || 'Input too long!',
      editDialog: false,
      showPracticeFilter: {
        default: true,
        type: Boolean
      },
      showSEFilter: {
        default: true,
        type: Boolean
      },
      showStatusFilter: {
        default: true,
        type: Boolean
      },
      projectType: {
        type: String,
        default: 'active'
      },
      disablePagination: {
        type: Boolean,
        default: true
      },
    },
  },
  methods: {
  ...mapActions('projects', {
        saveProject: 'saveProject',
    }), 
    save() {
      // Update API and store with new data.
      this.saveProject({
        projectType: this.projectType,
        projectData: this.editedItem
      })
  },
  computed: {
      statuses()  {
        return this.projectType === 'active' ? this.activeStatuses : this.oppStatuses;
      },
      filteredItems() {
        return this.items.filter(d => {
          return Object.keys(this.filters).every(f => {
            return this.filters[f].length < 1 || this.filters[f].includes(d[f])
          })
        })
      },
    }

ed ecco il codice pertinente dal componente genitore:

<v-card>
  <BaseProjectTable
    :headers="headers"
    :items="activeProjects"
    :loggedInUser="loggedInUser"
    title="Active Projects"
    :disablePagination=false
  ></BaseProjectTable>
</v-card>
...
export default {
  computed: {
    ...mapGetters('projects', {
      activeProjects: 'activeProjects',
      closedProjects: 'closedProjects',
      opportunities: 'opportunities'
    }),
  }
}

Il save()metodo aggiorna i dati nel mio negozio Vuex a cui fa riferimento il activeProjectsmap getter (ho verificato in Vue devtools che questo è vero). Mostra anche il itemsvalore nel componente stesso aggiornato nella Componentsscheda negli strumenti di sviluppo. Poiché l'utilizzo mapGettersrende i dati reattivi, mi aspettavo che aggiornerà anche i dati nel mio componente figlio, ma non è così.

Sulla base di quello che ho visto qui , ho provato la item-keyproprietà del <in questo v-data-table>modo:

<v-data-table
  show-expand
  :headers="headers"
  :items="filteredItems"
  :search="search"
  item-key="sow"
  @click:row="rowClick"
  :hide-default-footer="disablePagination"
  dense
  :disable-pagination="disablePagination"
>

(ogni record che utilizza questo componente avrà la sowchiave univoca ), ma non ha funzionato.

L'unico pensiero a cui potrei pensare è come sto modificando i dati nella mia mutazione:

export const state = () => ({
    active: [],
    closed: [],
    opportunities: [],
})

export const getters = {
  activeProjects: state => state.active,
  closedProjects: state => state.closed,
  opportunities: state => state.opportunities,
}

export const actions = {
  saveProject({ commit }, {projectType, projectData}) {
    commit(types.SAVE_PROJECT, {projectType, projectData});
  }
}

export const mutations = {
  [types.SAVE_PROJECT](state, {projectType, projectData}) {
    // Get project from state list by sow field.
    const index = state[projectType].findIndex(p => p.sow === projectData.sow);
    state[projectType][index] = projectData;
  }
}

rispetto alla sostituzione dell'intero state[projectType]valore.

Cosa devo fare per fare in modo che la tabella dati visualizzi il mio valore aggiornato?

Risposte

Tony Aug 21 2020 at 12:40

Dalla documentazione di Vue ,

Vue non è in grado di rilevare le seguenti modifiche a un array

  • Quando imposti direttamente un elemento con l'indice, ad es. Vm.items [indexOfItem] = newValue
  • Quando si modifica la lunghezza dell'array, ad esempio vm.items.length = newLength

Sostituisci quello che hai con

import Vue from 'vue'; // this should be at the top level

export const mutations = {
  [types.SAVE_PROJECT](state, {projectType, projectData}) {
    // Get project from state list by sow field.
    const index = state[projectType].findIndex(p => p.sow === projectData.sow);
    Vue.set(state[projectType], index, projectData)
  }
}

Successivamente, le modifiche all'array verranno rilevate e il getter funzionerà come previsto.