Vuexの更新後に、子コンポーネントで小道具を強制的に更新します

Aug 21 2020

<BaseProjectTable>Vuetify<v-data-table>コンポーネントを含むサイト全体で再利用される子コンポーネント()があります。データテーブルのヘッダーとコンテンツアイテムは小道具としてコンポーネントに渡され、アイテムデータはmapGetterVuexストアからのとして親にマップされます。子コンポーネントには各行の編集機能が含まれておりmapAction、そこからAPIとVuexデータを更新するためにを使用しています。これは、mapGetterがリアクティブであるため、データを更新し、データテーブルの表示を更新する必要があるという考えです。ただし、これは機能していません。開発ツールを介して、状態が正常に更新されていることがわかりますが、子コンポーネントの表示はそうではありません。

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

親コンポーネントの関連コードは次のとおりです。

<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()メソッドは、activeProjectsマップゲッターによって参照されるVuexストア内のデータを更新します(これが正しいことをVue devtoolsで確認しました)。また、開発ツールのタブでitems更新されたコンポーネント自体の値も表示されComponentsます。を使用mapGettersするとデータがリアクティブになるため、子コンポーネントのデータも更新されると予想しましたが、更新されません。

ここで見たものに基づいてitem-key、<のプロパティを次のv-data-table>ように試しました。

<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]値全体を置き換える場合と比較して。

更新された値を表示するためにデータテーブルを取得するには、何をする必要がありますか?

回答

Tony Aug 21 2020 at 12:40

Vueのドキュメントから、

Vueは、アレイに対する次の変更を検出できません

  • インデックスを使用してアイテムを直接設定する場合(例:vm.items [indexOfItem] = newValue)
  • 配列の長さを変更する場合(例: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)
  }
}

この後、アレイへの変更が検出され、ゲッターは期待どおりに機能します。