AG Grid异步请求后CellRenderer未获取更新数据问题排查
问题根因
你将列配置columnDefs通过useState初始化时,仅在组件首次渲染阶段捕获了当时judete的初始值(空数组)。后续异步请求完成更新judete状态时,存在state中的columnDefs不会自动重新计算,传给自定义CellRenderer的cellRendererParams始终保留初始化时的空数组引用,因此CellRenderer永远拿不到更新后的数据。
除此之外,AG Grid本身默认做了渲染性能优化,即使你手动更新了columnDefs,已经渲染完成的CellRenderer如果没有配置刷新逻辑,也不会主动重渲染拿新参数。
修复方案
以下两种方案都可以解决问题,优先选第二种,维护成本更低、性能更好。
方案1:用useMemo生成随数据更新的列配置
- 移除原来存columnDefs的useState,改用
useMemo生成列配置,把judete加入依赖项,保证judete更新时列配置同步生成最新值 - 在自定义CellRenderer上实现AG Grid要求的
refresh静态方法,返回true告知Grid参数更新时需要重渲染组件 - 给option标签加上唯一key属性,避免React渲染列表时出现异常
父组件Localitati对应修改部分:
// 原代码:const [columnDefs] = useState([...]) // 替换为以下代码 const columnDefs = useMemo(() => [ { field: "nume", filter: "agTextColumnFilter", editable: true }, { field: "judet", filter: "agTextColumnFilter", editable: true, cellRenderer: SelectJudetCellRenderer, cellRendererParams: { judete: judete } }, ], [judete]);
自定义CellRenderer修改后代码:
import { ICellRendererParams } from 'ag-grid-community'; export interface JudeteCellRendererParams extends ICellRendererParams { judete: any[]; } function SelectJudetCellRenderer(props: JudeteCellRendererParams) { return ( <select name="judete"> { props.judete.map((judet) => <option key={judet.id} value={judet.id}>{judet.name}</option> ) } </select> ) } // 实现refresh方法,参数变更时触发组件重渲染 SelectJudetCellRenderer.refresh = () => true; export default SelectJudetCellRenderer;
方案2:通过AG Grid的context传动态参数(推荐)
AG Grid原生提供了context配置项专门用来传递会动态更新的全局参数,不需要反复更新columnDefs,实现更简洁:
- 列配置固定写死即可,不需要依赖judete状态,也不需要在cellRendererParams里传judete
- 把动态变化的judete数据放在Grid组件的
context属性中传递 - 拿到Grid实例,judete数据加载完成后主动刷新judet列的单元格
- CellRenderer直接从
props.context中取最新的judete数据即可
父组件修改后完整代码:
import { useEffect, useMemo, useState, useRef } from "react"; import "ag-grid-community/dist/styles/ag-grid.min.css"; import "ag-grid-community/dist/styles/ag-theme-material.min.css"; import Grid from "../Common/Grid"; import axios from "axios"; import SelectJudetCellRenderer from "./SelectJudetCellRenderer"; function GetJudete() { return axios .get("http://localhost:5266/api/judete") .then((response) => response.data) .catch((err) => { console.log("Eroare la aducerea datelor."); return []; // 接口异常时返回空数组,避免后续map报错 }); } function Localitati() { let [judete, setJudete] = useState([]); const gridRef = useRef(null); // 存储Grid实例 useEffect(() => { async function GetJudeteAsync() { const result = await GetJudete(); setJudete(result); // 数据加载完成后,刷新judet列的所有单元格 if (gridRef.current?.api) { gridRef.current.api.refreshCells({ columns: ["judet"] }); } } GetJudeteAsync(); }, []); // 列配置固定,不需要存state、不需要依赖judete const columnDefs = [ { field: "nume", filter: "agTextColumnFilter", editable: true }, { field: "judet", filter: "agTextColumnFilter", editable: true, cellRenderer: SelectJudetCellRenderer }, ]; return ( <Grid ref={gridRef} baseLink="http://localhost:5266/api/localitati" columnDefs={columnDefs} context={{ judete: judete }} // 动态数据通过context传递 /> ); } export default Localitati;
自定义CellRenderer修改后代码:
import { ICellRendererParams } from 'ag-grid-community'; export interface JudeteCellRendererParams extends ICellRendererParams { context: { judete: any[] } } function SelectJudetCellRenderer(props: JudeteCellRendererParams) { const judete = props.context.judete; return ( <select name="judete"> { judete.map((judet) => <option key={judet.id} value={judet.id}>{judet.name}</option> ) } </select> ) } SelectJudetCellRenderer.refresh = () => true; export default SelectJudetCellRenderer;
排错提示:如果做完以上修改还是拿不到最新数据,检查下你封装的
../Common/Grid组件有没有对传入的columnDefs、context做深拷贝或者内部缓存,内部缓存会导致外部传入的更新值被覆盖。
内容的提问来源于stack exchange,提问作者Octavian Niculescu
相关产品推荐
相关产品推荐

