Forzar la actualización de los accesorios en el componente secundario después de la actualización de Vuex
Tengo un componente secundario ( <BaseProjectTable>
) que se reutiliza en todo mi sitio y que contiene un <v-data-table>
componente de Vuetify . Los encabezados y los elementos de contenido de la tabla de datos se pasan al componente como accesorios, y los datos del elemento se asignan al padre como mapGetter
desde una tienda Vuex. El componente secundario contiene funcionalidad de edición para cada fila, y estoy usando mapAction
para actualizar la API y los datos de Vuex desde allí, con la idea de que, dado que mi mapGetter es reactivo, debería actualizar los datos y, por lo tanto, la visualización de la tabla de datos. Sin embargo, esto no está funcionando; Puedo ver a través de las herramientas de desarrollo que el estado está actualizado muy bien, pero la pantalla del componente secundario no.
Aquí está la parte relevante del <BaseProjectTable>
componente secundario :
<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])
})
})
},
}
y aquí está el código relevante del componente principal:
<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'
}),
}
}
El save()
método actualiza los datos en mi tienda Vuex a los que hace referencia el activeProjects
captador de mapas (he verificado en las herramientas de desarrollo de Vue que esto es cierto). También muestra el items
valor en el propio componente actualizado en la Components
pestaña de las herramientas de desarrollo. Dado que el uso mapGetters
hace que los datos sean reactivos, esperaba que también actualizara los datos en mi componente secundario, pero no es así.
Basado en lo que vi aquí , probé la item-key
propiedad de < v-data-table>
así:
<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"
>
(cada registro que use este componente tendrá la sow
clave única ), pero eso no funcionó.
Lo único que podría pensar es cómo estoy editando los datos en mi mutación:
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;
}
}
en comparación con reemplazar todo el state[projectType]
valor.
¿Qué debo hacer para que la tabla de datos muestre mi valor actualizado?
Respuestas
De la documentación de Vue ,
Vue no puede detectar los siguientes cambios en una matriz
- Cuando establece directamente un elemento con el índice, por ejemplo, vm.items [indexOfItem] = newValue
- Cuando modifica la longitud de la matriz, por ejemplo, vm.items.length = newLength
Reemplaza lo que tienes 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)
}
}
Después de esto, se detectarán los cambios en la matriz y el captador funcionará como se esperaba.