React函数组件中无法在AgGrid cellRenderer内访问组件状态
问题:React函数组件中AgGrid的cellRenderer无法访问更新后的myObj状态
我在使用函数组件的React应用中,通过父组件的context对象(基于API响应)填充本地状态myObj,并用该状态填充AgGrid。网格里通过cellRenderer实现了行级编辑链接,但在cellRenderer内访问myObj时得到的是空对象{}。我试过添加cellRendererParams: {myObj: myObj},但还是没解决,请问还要做什么才能在cellRenderer中访问函数组件的状态?
原代码
function MyChildComponent(props) { const [gridData, setGridData] = useState([]); const [myObj, setMyObj] = useState({ gridItems: [{ fields: [{ field1: {}, field2: {} }] }] }); useEffect(() => { //API call to set myObj with data (includes grid data within the API response) }, [myContextObjWithData]); useEffect(() => { if (myObj && myObj.gridItems && myObj.gridItems.length > 0) { setGridData([{ 'field1': 'Primary', 'field2': 'F1' }, { 'field1': 'Secondary', 'field2': 'F2' }]) } }, [myObj]) setMyColumns([ { headerName: 'Col 1', field: 'field1' }, { headerName: 'Col 2', field: 'field2' }, { headerName: '', field: '', cellRendererParams: {myObj: myObj}, cellRenderer: (params) => { console.log(myObj); // Returns empty object } } ]) return ( <> <MyAgGrid id="myGrid" columnDefs={myColumns} rowData={gridData} {...props} /> </> ); }
问题原因
- 你直接在组件函数体中调用
setMyColumns,但未用useState声明myColumns状态,这本身会导致报错。 - 即使声明了状态,直接在函数体中创建列定义会让cellRenderer捕获初始渲染时的
myObj闭包值,后续myObj更新后,列定义未同步更新,cellRenderer仍使用旧的闭包值。
修复方案
方案1:用useState+useEffect管理列定义
通过useEffect监听myObj变化,每次myObj更新时重新生成列定义并更新状态,确保cellRenderer能拿到最新的myObj:
function MyChildComponent(props) { const [gridData, setGridData] = useState([]); const [myObj, setMyObj] = useState({ gridItems: [{ fields: [{ field1: {}, field2: {} }] }] }); // 声明列定义状态 const [myColumns, setMyColumns] = useState([]); useEffect(() => { // API call to set myObj with data (includes grid data within the API response) }, [myContextObjWithData]); useEffect(() => { if (myObj && myObj.gridItems && myObj.gridItems.length > 0) { setGridData([{ 'field1': 'Primary', 'field2': 'F1' }, { 'field1': 'Secondary', 'field2': 'F2' }]); } }, [myObj]); // 监听myObj变化,更新列定义 useEffect(() => { const newColumns = [ { headerName: 'Col 1', field: 'field1' }, { headerName: 'Col 2', field: 'field2' }, { headerName: '', field: '', cellRendererParams: { myObj: myObj }, cellRenderer: (params) => { // 通过params访问最新的myObj console.log(params.myObj); // 此时直接访问myObj也能拿到最新值,因为useEffect依赖了myObj console.log(myObj); } } ]; setMyColumns(newColumns); }, [myObj]); return ( <> <MyAgGrid id="myGrid" columnDefs={myColumns} rowData={gridData} {...props} /> </> ); }
方案2:用useMemo生成列定义(更推荐)
使用useMemo缓存列定义,依赖myObj,这样只有当myObj变化时才会重新生成列定义,既保证数据更新,又优化性能:
function MyChildComponent(props) { const [gridData, setGridData] = useState([]); const [myObj, setMyObj] = useState({ gridItems: [{ fields: [{ field1: {}, field2: {} }] }] }); useEffect(() => { // API call to set myObj with data (includes grid data within the API response) }, [myContextObjWithData]); useEffect(() => { if (myObj && myObj.gridItems && myObj.gridItems.length > 0) { setGridData([{ 'field1': 'Primary', 'field2': 'F1' }, { 'field1': 'Secondary', 'field2': 'F2' }]); } }, [myObj]); // 用useMemo生成列定义,依赖myObj const myColumns = useMemo(() => [ { headerName: 'Col 1', field: 'field1' }, { headerName: 'Col 2', field: 'field2' }, { headerName: '', field: '', cellRendererParams: { myObj: myObj }, cellRenderer: (params) => { // 优先通过params访问最新的myObj console.log(params.myObj); } } ], [myObj]); return ( <> <MyAgGrid id="myGrid" columnDefs={myColumns} rowData={gridData} {...props} /> </> ); }
关键注意点
- AgGrid的列定义如果依赖组件状态,必须让列定义随状态同步更新,否则cellRenderer会一直使用初始渲染时的闭包值。
- 在cellRenderer中通过
params.cellRendererParams.myObj访问是最可靠的方式,避免闭包陷阱。 - 使用
useMemo可以减少不必要的列定义重新创建,提升组件性能。
内容的提问来源于stack exchange,提问作者copenndthagen
相关产品推荐
相关产品推荐

