我遇到了在略微嵌套的数据结构中更新Vuex存储中的数据的问题。
我的整个项目比下面的要复杂一些,但是我现在遇到的问题已得到简化和设置,因此对于每个项目页面,都会有一个登录页面,包含表格可见性和单个表格组件,其中包含一个Vuetify v-data-table元素,该元素仅将标头和项目作为道具和显示它们。可以通过以下形式将其可视化:
- Project Page
|- Landing page
|- Table Visibility
|- Table Component
|- v-data-table
一种考虑方式如下: 对于每种动物(项目页面),都有三种不同的品种/类型,每种都有不同的特征。因此,上述结构将变为:
- Dog
|- Landing page
|- Table Visibility
|- German Shepherd
|- v-data-table
|- Bull Terrier
|- v-data-table
|- Labrador Retriever
|- v-data-table
- Cat
|- Landing page
|- Table Visibility
|- Russian Blue
|- v-data-table
|- British Shorthair
|- v-data-table
|- Persian
|- v-data-table
- Bird
|- Landing page
|- Table Visibility
|- Cockatiel
|- v-data-table
|- Parrot
|- v-data-table
|- Macaw
|- v-data-table
当用户导航到任何项目页面时,他或她将能够通过表可见性组件选择哪些表是可查看的。该组件看起来像这样:
<template>
<div>
<v-card>
<v-card-title>
<p class="title ma-0">Table Visibility</p>
</v-card-title>
<v-divider class="mx-5"></v-divider>
<v-card-text>
<v-layout row wrap fill-height>
<v-checkbox
v-for="(title, idx) in tableTitles"
v-model="tableVisibility"
:label="title"
:value="title"
:key="idx"
class="mx-1"
multiple
></v-checkbox>
</v-layout>
</v-card-text>
<v-card-actions>
<v-switch
v-model="showAll"
:label="showAll ? 'Hide All' : 'Show All'"
></v-switch>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: "TableChoices",
props: ['tableTitles'],
data() {
return {
showAll: false,
displayTables: [],
}
},
methods: {
},
computed: {
...mapState({
pageName: state => state.pageName,
}),
},
watch: {
showAll(bool) {
bool ?
this.displayTables = this.tableTitles :
this.displayTables = []
},
displayTables: {
handler() {
let tableObj = {};
this.tableTitles.forEach(title => { tableObj[title] = this.displayTables.indexOf(title) > -1 })
this.$store.commit('setTableVisibility', {page: this.pageName, tables: tableObj})
if (this.displayTables.length === this.tableTitles.length) {
this.showAll = true
} else if (this.displayTables.length === 0) {
this.showAll = false
}
}
},
}
}
</script>
<style scoped>
</style>
<template>
<div>
</div>
</template>
<script>
import Dog from '@/components/Dog'
import Cat from '@/components/Cat'
import Bird from '@/components/Bird'
import { mapState, mapGetters } from 'vuex'
export default {
name: "LandingPage",
components: {
Dog,
Cat,
Bird,
},
data() {
return {
items: {},
headers: {},
}
},
computed: {
...mapState({
pageName: state => state.pageName,
}),
...mapGetters({
tableVisibility: 'getTableVisibility'
})
},
watch: {
tableVisibility: {
handler() { console.log('tableVisibility in LandingPage.vue', this.tableVisibility)},
deep: true
},
}
}
</script>
<style scoped>
</style>
放置Dog,Cat或Bird组件没有意义,因为它们只保留Vuetify数据表,因此它们基本上可以由占位符简单地使用,因为它们并不重要。
商店的设置如下:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export const debug = process.env.NODE_ENV !== 'production'
function initialState() {
return {
pageItems: {},
pageHeaders: {},
pageName: '',
tableTitles: {
Dog: ['German Shepherd', 'Bull Terrier', 'Labrador Retriever'],
Cat: ['Russian Blue', 'British Shorthair', 'Persian'],
Bird: ['Cockatiel', 'Parrot', 'Macaw']
},
tableVisibility: {
Dog: {
German Shepherd: false,
Bull Terrier: false,
Labrador Retriever: false
},
Cat: {
Russian Blue: false,
British Shorthair: false,
Persian: false
},
Bird: {
Cockatiel: false,
Parrot: false,
Macaw: false
}
}
}
}
const state = {...initialState()}
const mutations = {
setTableVisbility(state, payload) {
const page = payload.page;
const tables = payload.tables;
// Vue.set(state.tableVisibility, page, tables)
state.tableVisibility[page] = Object.assign({}, tables);
}
}
const getters = {
getTableVisibility: (state) => ( state.tableVisibility[state.PageName] ),
getCurrentPageTableTitles: (state) => ( state.tableTitles[state.pageName] ),
}
export default new Vuex.Store({state, mutations, getters, strict: debug})
就像我说的那样,整个项目要比这复杂得多(我在这里显示的商店功能实际上是在模块中,等等),但是我什至在LandingPage.vue中获取tableVisibility的更新值时都遇到了麻烦零件。我正在尝试将 deep 处理程序应用于观察者的几种不同方法(https://vuejs.org/v2/api/#watch和https://medium.com/@stijlbreuk/six-random-issues-and-their-solutions-in-vuejs-b16d470a6462);我试图通过使用拼接(How do I empty an array in JavaScript?)清除数组,然后将所有元素推回到数组中来拆分存储中的数组功能。我尝试使用 filter 数组方法尝试创建一个新数组;我尝试将tableVisibility存储为一个对象(表名作为键,值存储为true或false),以便可以使用Object.assign(https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats);我已经找到了有关规范化数据(https://forum.vuejs.org/t/vuex-best-practices-for-complex-objects/10143/2)的页面,但看上去它并不复杂到已经很简单的程度。
我精疲力尽,想弄清楚发生了什么,我非常感谢您的帮助。
我已经更新了项目,使其包含吸气剂,反应性在tableVisibility值之外的所有其他组件中都起作用。我尝试将tableVisibility元素保留为数组,然后尝试将其转换为对象,如本次编辑所示,然后尝试使用Vue.set更新值,但该方法不起作用,然后尝试使用Object.assign如当前版本所示。如果我离开页面然后返回更新值,则尽管我尝试使用Vue.set和Object.assign,但它们似乎正在失去反应性。
答案 0 :(得分:1)
我对您的建议是开始考虑标准化数据。一些大问题是:
tableVisibility
也是如此。首先,编写吸气剂方法和变异方法;使它们足够通用,以便您可以在Vue组件中的任何地方重用,并强制所有Vue组件使用它们,而不是直接访问状态
示例:
const getters = {
getCurrentActivePage: (state) => {}, // return pageName
getProjects: (state) => {},
getProjectById: (state) => (projectId) => {},
getTablesOfProjects: (state) => (projectId) => {},
getTable: (state) => (tableID) => {},
isTableVisible: (state) => (tableID) => {}
}
const mutations = {
setTableVisibility: (state, { tableID, newValue }) => {}
}
在将UI逻辑与状态结构分离之后,可以开始标准化状态数据。尝试将您的状态视为一个小型数据库,并进行逻辑设计。一种方法是这样的:
const state = {
pageName: '',
projects: {
'123': { id: '123', name: 'Dog' },
'234': { id: '234', name: 'Cat' }
// ...
},
tables: {
'123z': { id: '123z', projectId: '123', name: 'German Shepherd', visible: false }
}
}
其中的id可以使用诸如nanoid之类的npm软件包自动生成。
即使没有规范化,我仍然建议您执行步骤1(去耦)。如果商店很复杂,则无法确定修改商店的状态是否会导致Vue组件崩溃。好的getters
和mutations
将至少捕获无效数据并返回组件的默认值。