Vue3中无法用Vuex Getter数据填充ag-grid问题排查
尝试使用Vuex Getter返回的异步数据填充ag-grid组件,调试时能看到Getter已有数据,但网格的rowData属性仍为空,同时控制台出现以下警告和错误:
警告信息
runtime-core.esm-bundler.js:38 [Vue warn]: Unhandled error during execution of mounted hook
at <Anonymous class="ag-theme-alpine" id="myGrid" columnDefs= {value: Array(7)} ... >
at
at <DesignSystem onVnodeUnmounted=fn ref=Ref< Proxy {callWebsocket: ƒ, sendMessage: ƒ, …} > >
at
at
at <ConfigProvider theme-overrides= {common: {…}, Checkbox: {…}, Radio: {…}, Button: {…}, Switch: {…}} theme=null >
错误信息
Uncaught (in promise) TypeError: this.gridOptions.columnDefs.forEach is not a function
at GridOptionsWrapper2.checkColumnDefProperties (ag-grid-community.cjs.js:18300:37)
at GridOptionsWrapper2.init (ag-grid-community.cjs.js:18240:18)
at ag-grid-community.cjs.js:1113:76
at Array.forEach ()
at Context2.callLifeCycleMethodsOnBean (ag-grid-community.cjs.js:1113:24)
at ag-grid-community.cjs.js:1096:70
at Array.forEach ()
at Context2.callLifeCycleMethods (ag-grid-community.cjs.js:1096:23)
at Context2.wireBeans (ag-grid-community.cjs.js:975:14)
at new Context2 (ag-grid-community.cjs.js:953:14)
组件模板
<template> <div class="test-container"> <ag-grid-vue class="ag-theme-alpine" id="myGrid" :columnDefs="columnDefs" domLayout="autoHeight" unSortIcon="true" @grid-ready="onGridReady" :animateRows="true" :rowData="rowData" :defaultColDef="defaultColDef" > </ag-grid-vue> </div> </template>
Setup函数(Vue3组合式API)
import { AgGridVue } from "ag-grid-vue3"; import { useActions, useGetters } from "vuex-composition-helpers"; import { reactive, onMounted, ref } from "vue"; export default { components: { AgGridVue, }, setup() { const gridApi = ref(null); const onGridReady = (params) => { gridApi.value = params.api; }; const rowData = reactive([]); const columnDefs = reactive({ value: [ { field: "brandId", sortable: true, checkboxSelection: true }, { field: "category" }, { field: "channel", headerName: "Brand" }, { field: "channelReferenceId", headerName: "Requested" }, { field: "id", headerName: "Updated" }, { field: "status", headerName: "Subject" }, { field: "subject", headerName: "Requester" }, ], }); const defaultColDef = { sortable: true, filter: true, flex: 1, }; const { fetchTickets } = useActions({ fetchTickets: "tickets/fetchTickets", }); const { tickets } = useGetters({ tickets: "tickets/getRowData", }); function getTickets() { fetchTickets(); } getTickets(); onMounted(() => { rowData.value = tickets.value; }); return { onGridReady, columnDefs, rowData, defaultColDef, tickets, getTickets, }; },
使用vuex-composition-helpers从API获取Tickets数据,通过Getter作为数据源填充ag-grid。
1. 修复columnDefs类型错误
控制台核心错误columnDefs.forEach is not a function,原因是你把columnDefs定义成了包含value属性的响应式对象,但ag-grid要求columnDefs必须是数组类型。
修改方式:直接将columnDefs定义为响应式数组:
// 替换原columnDefs定义 const columnDefs = reactive([ { field: "brandId", sortable: true, checkboxSelection: true }, { field: "category" }, { field: "channel", headerName: "Brand" }, { field: "channelReferenceId", headerName: "Requested" }, { field: "id", headerName: "Updated" }, { field: "status", headerName: "Subject" }, { field: "subject", headerName: "Requester" }, ]);
模板中保持:columnDefs="columnDefs"即可,无需改动。
2. 修复rowData的赋值与异步数据监听
- 用
reactive([])定义的rowData是数组,不能通过rowData.value赋值(这是ref的用法),需要直接操作数组内容。 - 异步数据
tickets在onMounted时可能还未返回,仅单次赋值无法响应后续数据变化,需要用watch监听tickets的更新,实时同步到rowData。
修改步骤:
- 导入
watch:
import { reactive, onMounted, ref, watch } from "vue";
- 添加监听逻辑,替换原
onMounted中的赋值代码:
const rowData = reactive([]); // 监听tickets变化,实时更新rowData watch(tickets, (newTickets) => { // 清空原数组并添加新数据 rowData.splice(0, rowData.length, ...newTickets); }, { immediate: true }); // immediate: true 确保初始化时执行一次
3. 优化数据加载时机(可选)
可以在网格初始化完成后(onGridReady回调中)再触发数据请求,避免网格未就绪就加载数据:
const onGridReady = (params) => { gridApi.value = params.api; // 网格就绪后请求数据 getTickets(); }; // 移除原来的getTickets()调用
修改后的完整Setup函数
import { AgGridVue } from "ag-grid-vue3"; import { useActions, useGetters } from "vuex-composition-helpers"; import { reactive, onMounted, ref, watch } from "vue"; export default { components: { AgGridVue, }, setup() { const gridApi = ref(null); const onGridReady = (params) => { gridApi.value = params.api; getTickets(); }; const rowData = reactive([]); const columnDefs = reactive([ { field: "brandId", sortable: true, checkboxSelection: true }, { field: "category" }, { field: "channel", headerName: "Brand" }, { field: "channelReferenceId", headerName: "Requested" }, { field: "id", headerName: "Updated" }, { field: "status", headerName: "Subject" }, { field: "subject", headerName: "Requester" }, ]); const defaultColDef = { sortable: true, filter: true, flex: 1, }; const { fetchTickets } = useActions({ fetchTickets: "tickets/fetchTickets", }); const { tickets } = useGetters({ tickets: "tickets/getRowData", }); function getTickets() { fetchTickets(); } watch(tickets, (newTickets) => { rowData.splice(0, rowData.length, ...newTickets); }, { immediate: true }); return { onGridReady, columnDefs, rowData, defaultColDef, tickets, getTickets, }; },
内容的提问来源于stack exchange,提问作者Lowtrux

