在 Vuex 更新后强制 props 在 child 组件中更新

Force props to update in child component after Vuex update

我的站点中有一个 child 组件 (<BaseProjectTable>) re-used,其中包含一个 Vuetify <v-data-table> 组件。数据 table 的 headers 和内容项作为 props 传递到组件中,项数据作为 Vuex 存储中的 mapGetter 映射到 parent . child 组件包含每一行的编辑功能,我正在使用 mapAction 从那里更新 API 和 Vuex 数据,因为我的 mapGetter 是反应式的,它应该更新数据并因此更新数据 table 显示。但是,这是行不通的;我可以通过开发工具看到状态更新得很好,但 child 组件显示不是。

这是 child <BaseProjectTable> 组件的相关部分:

<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])
          })
        })
      },
    }

这里是 parent 组件的相关代码:

<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'
    }),
  }
}

save() 方法更新了我的 Vuex 存储中被 activeProjects 映射 getter 引用的数据(我已经在 Vue devtools 中验证这是真的)。它还显示组件本身的 items 值在开发工具的 Components 选项卡中更新。由于使用 mapGetters 使数据具有反应性,我预计它也会更新我的 child 组件中的数据,但它没有。

根据我看到的 here,我尝试了 <v-data-table>item-key 属性,如下所示:

<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"
>

(使用此组件的每条记录都将具有唯一的 sow 键),但这没有用。

我唯一能想到的是我如何在我的突变中编辑数据:

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;
  }
}

与替换整个 state[projectType] 值相比。

我需要做什么才能让数据table显示我的更新值?

来自 Vue documentation,

Vue cannot detect the following changes to an array

  • When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
  • When you modify the length of the array, e.g. vm.items.length = newLength

将现有的替换为

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)
  }
}

在此之后,将检测到数组的更改,并且 getter 将按预期工作。