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

如何将React函数组件转为AgGrid要求的new() => any类型?

AgGridReact 自定义函数组件过滤器类型不匹配问题解决

问题场景

在给AgGridReact实现自定义过滤器时,无论是将函数组件赋值给frameworkComponents:

frameworkComponents: {
   newcustomFilter: CustomFilter
},

还是直接在columnDefs中指定filter: CustomFilter,都会触发相同的TypeScript错误:

Type '(props: any) => JSX.Element' is not assignable to type 'new () => any'.
  Type '(props: any) => Element' provides no match for the signature 'new (): any'.ts(2322)

我的自定义过滤器是React函数组件,代码如下:

import React from 'react'
import { useEffect, useState } from "react";

const CustomFilter = (props:any):any => {   
    const [filterState, setFilterState] = useState('off');

    useEffect( ()=> {
        console.log(props.title + ' filter created');
        return ()=> console.log(props.title + ' filter destroyed');
    }, []);

    useEffect( ()=> {
        props.filterChangedCallback()
    }, [filterState]);

    const handleChange = (e:any) => {
        setFilterState(e.target.value)
    }

    const isFilterActive = () => {
        return filterState!='off';
    }

    const doesFilterPass = (params:any) => {
        const field = props.colDef.field;
        return params.data[field] == filterState;
    }
    
    const getModel =() => {
        if (filterState=='off') { 
            return undefined;
        }
        return { state: filterState }
    }
    
    const setModel = (model:any) => {
        if (model==null) {
            setFilterState('off');
        } else {
            setFilterState(model.state);
        }
    }
    
    const getModelAsString = () => {
        return filterState=='off' ? '' : filterState;
    }
    
    const onNewRowsLoaded = () => {
        console.log('new rows were loaded');
    }
    
    const onAnyFilterChanged = () => {
        console.log('another filter was changed');
    }

    const afterGuiAttached = () => {
        console.log('focus something???');
    }   

    return (
        <div>
            <div className='filter-title'>{props.title}</div>
            <div className='filter-state'>State = {filterState}</div>
            <div className='filter-entry'>
                <button onClick={()=>setFilterState('off')}>Off</button>
            </div>
            
            <select onChange={handleChange}>
                {props.values.map((option:any) => (
                    <option key={option.value} value={option.value}>
                        {option.text}
                    </option>
                ))}
            </select>
        </div>
    );
}

问题原因

AgGrid的自定义过滤器要求组件是可实例化的构造函数类型(即类组件,符合new() => any签名),而React函数组件是无状态的函数,不具备构造函数特性,因此类型不匹配。

解决方案

方案1:用forwardRef + useImperativeHandle适配函数组件(推荐)

通过React的forwardRef和useImperativeHandle,将AgGrid所需的过滤器方法暴露给Grid实例,同时保留函数组件的写法:

import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { IFilterComp, IFilterParams } from 'ag-grid-community';

// 使用forwardRef让AgGrid能获取到组件实例的方法
const CustomFilter = forwardRef<IFilterComp, IFilterParams>((props, ref) => {
    const [filterState, setFilterState] = useState('off');

    // 暴露IFilterComp接口要求的所有方法给AgGrid
    useImperativeHandle(ref, () => ({
        isFilterActive: () => filterState !== 'off',
        doesFilterPass: (params: any) => {
            const field = props.colDef.field;
            return params.data[field] === filterState;
        },
        getModel: () => filterState === 'off' ? undefined : { state: filterState },
        setModel: (model: any) => {
            setFilterState(model ? model.state : 'off');
        },
        getModelAsString: () => filterState === 'off' ? '' : filterState,
        onNewRowsLoaded: () => console.log('new rows were loaded'),
        onAnyFilterChanged: () => console.log('another filter was changed'),
        afterGuiAttached: () => console.log('focus something???')
    }));

    useEffect(() => {
        console.log(props.title + ' filter created');
        return () => console.log(props.title + ' filter destroyed');
    }, []);

    useEffect(() => {
        props.filterChangedCallback();
    }, [filterState]);

    const handleChange = (e: any) => {
        setFilterState(e.target.value);
    };

    return (
        <div>
            <div className='filter-title'>{props.title}</div>
            <div className='filter-state'>State = {filterState}</div>
            <div className='filter-entry'>
                <button onClick={() => setFilterState('off')}>Off</button>
            </div>
            
            <select onChange={handleChange}>
                {props.values.map((option: any) => (
                    <option key={option.value} value={option.value}>
                        {option.text}
                    </option>
                ))}
            </select>
        </div>
    );
});

// 设置displayName方便调试
CustomFilter.displayName = 'CustomFilter';

使用方式

  1. 在Grid的frameworkComponents中注册组件:
frameworkComponents: {
    customFilter: CustomFilter
},
  1. 在columnDefs中指定使用该过滤器(注意用注册的字符串名称,而非组件本身):
columnDefs: [
    {
        headerName: 'PRICE',
        field: WATERFALL_COLUMN_IDS.PRICE,
        colId: WATERFALL_COLUMN_IDS.PRICE,
        minWidth: 70,
        width: 92,
        hide: false,
        filter: 'customFilter', // 对应frameworkComponents中的键名
        filterParams: {
            title: 'Year Filter',
            values: [2000,2004,2006]
        },
    }
]

方案2:将函数组件转为类组件

如果更习惯类组件写法,可以直接将函数组件重构为实现IFilterComp接口的类组件:

import React, { Component } from 'react';
import { IFilterComp, IFilterParams } from 'ag-grid-community';

class CustomFilter extends Component<IFilterParams, { filterState: string }> implements IFilterComp {
    constructor(props: IFilterParams) {
        super(props);
        this.state = { filterState: 'off' };
    }

    isFilterActive(): boolean {
        return this.state.filterState !== 'off';
    }

    doesFilterPass(params: any): boolean {
        const field = this.props.colDef.field;
        return params.data[field] === this.state.filterState;
    }

    getModel(): any {
        return this.state.filterState === 'off' ? undefined : { state: this.state.filterState };
    }

    setModel(model: any): void {
        this.setState({ filterState: model ? model.state : 'off' });
    }

    getModelAsString(): string {
        return this.state.filterState === 'off' ? '' : this.state.filterState;
    }

    onNewRowsLoaded(): void {
        console.log('new rows were loaded');
    }

    onAnyFilterChanged(): void {
        console.log('another filter was changed');
    }

    afterGuiAttached(): void {
        console.log('focus something???');
    }

    componentDidMount(): void {
        console.log(this.props.title + ' filter created');
    }

    componentWillUnmount(): void {
        console.log(this.props.title + ' filter destroyed');
    }

    componentDidUpdate(prevProps: IFilterParams, prevState: { filterState: string }): void {
        if (prevState.filterState !== this.state.filterState) {
            this.props.filterChangedCallback();
        }
    }

    handleChange = (e: any) => {
        this.setState({ filterState: e.target.value });
    }

    render() {
        const { filterState } = this.state;
        const { title, values } = this.props;
        return (
            <div>
                <div className='filter-title'>{title}</div>
                <div className='filter-state'>State = {filterState}</div>
                <div className='filter-entry'>
                    <button onClick={() => this.setState({ filterState: 'off' })}>Off</button>
                </div>
                
                <select onChange={this.handleChange}>
                    {values.map((option: any) => (
                        <option key={option.value} value={option.value}>
                            {option.text}
                        </option>
                    ))}
                </select>
            </div>
        );
    }
}

使用方式

直接在columnDefs中指定组件即可:

columnDefs: [
    {
        // ...其他配置
        filter: CustomFilter,
        filterParams: {
            title: 'Year Filter',
            values: [2000,2004,2006]
        },
    }
]

内容的提问来源于stack exchange,提问作者Raj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:25:25