如何将 Pinia 与表配置对象的 Map 一起使用

问题描述 投票:0回答:1

我正在使用 Pinia 来管理整个应用程序中不同数据表的状态。多个表可以在彼此“顶部”打开(即彼此重叠)。这就是为什么我正在重新设计我们当前的设置,其中只能打开一个表,另一个表将覆盖前一个表,到一个可以同时打开多个表的新系统。

我想到使用 Pinia 和 Map() 来保持所有数据表配置就位,并使用“activeDataTableName”字段来跟踪哪个表当前是“活动”表。

我的 Pinia 商店是这样的:

export const useDataTableStore = defineStore('data-table', {
  state: () => ({
    dataTables: new Map(), // use a Map to store all data table configurations
    activeDataTableName: null, // Used to track which is the current active data table
  }),
  getters: {
    getActiveDataTableConfig: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig || null
    },
    getDataTableName: (state) => state.activeDataTableName,
    getLoading: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig ? dtConfig.loading : true
    },
    getDataTableColumns: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig ? dtConfig.dataTableColumns : []
    },
    getTotalRecords: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig ? dtConfig.totalRecords : 0
    },
    getFirst: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig ? dtConfig.first : 0
    },
    getAmountRowsToShow: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig ? dtConfig.amountRowsToShow : 15
    },
    getSelectedRows: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig ? dtConfig.selectedRows : []
    },
    getFocussedRow: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig ? dtConfig.focussedRow : null
    },
    getLazyParams: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig ? dtConfig.lazyParams: {}
    }
    getSelectAll: (state) => {
      const dtConfig = state.dataTables.get(state.activeDataTableName)
      return dtConfig ? dtConfig.selectAll : false
    },
  },
  actions: {
    async initialize (nuxtApp, dtName) {
      // The initialize function sets the dataTableName and loads the columns
      const newDataTableConfigObject = {
        loading: true,
        dataTableName: dtName,
        dataTableColumns: [],
        totalRecords: 0,
        first: 0,
        amountRowsToShow: 15,
        selectedRows: [],
        focussedRow: null,
        lazyParams: {},
        selectAll: false,
      }
      this.dataTables.set(dtName, newDataTableConfigObject)
      this.activeDataTableName = dtName
    },
    setSelectedRows (rows) {
      const dtConfig = this.dataTables.get(this.activeDataTableName)
      if (dtConfig) {
        dtConfig.selectedRows = rows
      }
    },
  },
})

当我尝试使用 v-model 进行 2 路绑定时,出现了问题。 例如:我将有一个组件“DataTable”,它从 v 模型中的商店中获取值,如下所示:

<DataTable
        ref="dataTableRef"
        v-model:selection="store.selectedRows"
        v-model:first="store.first"
        v-model:rows="store.amountRowsToShow"
        ...
/>

当我的商店初始化时:

const store = useDataTableStore()

“selectedRows”、“first”等的值不会直接位于存储中,而是位于存储中数据表内的活动配置对象中。 当我尝试为商店的变量设置值时,我也遇到了困难:

store.amountRowsToShow = rows
store.lazyParams.first = store.getFirst
store.lazyParams.rows = store.getAmountRowsToShow

这可能可以通过每个特定的 setter 来解决,但是如果我必须为懒惰参数中的每个潜在对象创建一个 setter 方法,它就会变得非常乏味。难道没有更好的方法吗?

vue.js pinia
1个回答
0
投票

activeDataTableName
也没关系,尽管这个状态可能属于“活跃”的组件而不是store

getActiveDataTableConfig
这样的吸气剂存在一个根本问题。如果要同时呈现多个表,则无法使用 getter 来显示非活动表中的数据。如果存储中所有表都被平等对待,那么可能会导致更少的问题。参数化计算可用于此:

getters: {
  getSelectedRows: (state) => {
    return (name) => state.dataTables.get(name) || null;
  },
  ...

参数化计算不会被缓存,这对于性能密集型使用(表可能是这样)至关重要。可以使用为特定表创建计算的助手来代替参数化计算,或者除了参数化计算之外:

function mapStoreTable(name) {
  const store = useTableStore();
  const tableData = store.dataTables.get(name);
  
  const selectedRows = computed(() => store.getSelectedRows(name));
  ...
  return { selectedRows, ... };
}

这将使

selectedRows
等不会对其他表中的更改做出反应。

更新操作可以接受表名来更新特定的表:

  actions: {
    setSelectedRows(name, rows) {
      const dtConfig = this.dataTables.get(name);
      if (dtConfig) {
        dtConfig.selectedRows = rows
      }
    },
    ...

直接使用

v-model
改变商店通常是值得怀疑的做法。尽管 Pinia 中允许这样做,但之前在 Vuex 中不鼓励这样做,因为这会导致代码难以调试和维护。无论如何,使用建议的助手这是不可能的。
v-model
可以脱糖为道具和事件。或者可以创建一个可写的计算,它在集合上调度一个动作并可以用作
v-model:selection="selectedRowsModel"

const { selectedRows } = mapStoreTable(tableName);

const selectedRowsModel = computed({
  get() {
    return selectedRows.value;
  },
  set(rows) {
    store.setSelectedRows(name, rows) 
  }
});
© www.soinside.com 2019 - 2024. All rights reserved.