You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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}
            />
        
        </>
    ); 
}   

问题原因

  1. 你直接在组件函数体中调用setMyColumns,但未用useState声明myColumns状态,这本身会导致报错。
  2. 即使声明了状态,直接在函数体中创建列定义会让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 02:32:45