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

使用useCallback与memo避免子组件重复渲染问题求助

问题原因分析

1. useCallback依赖数组包含不必要变量

你的handleSelectedRow函数仅打印传入的参数,并未用到debounceFilter、columnDef_FilterCustomer、tbData、columnType_FilterCustomer、resetRowSelection这些变量,但它们被错误添加到了useCallback的依赖数组中。当这些变量的引用发生变化时(比如输入字符导致filterData更新,进而使debounceFilter引用变化),handleSelectedRow会被重新创建,传给子组件的handleSelectedRow成为新的函数引用。由于React.memo是浅比较,会判定props变化,触发子组件重渲染。

2. 冗余的tbData状态维护

你将useQuery返回的数据存入额外的tbData state中,导致两次状态更新:一次是useQuery返回数据,另一次是useEffect触发setTbData。这不仅增加了组件重渲染次数,还可能因tbData引用频繁变化,进一步触发子组件重渲染。

3. 输入触发父组件频繁重渲染(间接影响)

每次输入字符都会更新filterData,导致父组件重渲染。虽然防抖减少了useQuery的调用,但父组件本身仍会随每次输入重渲染。如果子组件的props中存在任何随父组件重渲染而变化的引用,就会触发子组件重渲染。

解决方案

1. 清理useCallback依赖数组

由于handleSelectedRow内部未使用任何外部变量,直接清空依赖数组即可:

const handleSelectedRow = useCallback((tbCustomerSeletedRow) => {
    console.log(tbCustomerSeletedRow)
}, []);

这样handleSelectedRow的引用会保持稳定,不会随父组件重渲染而变化。

2. 移除tbData状态,直接使用useQuery返回值

无需将useQuery结果存入额外state,直接将查询结果传给子组件:

// 移除tbData的state和对应的useEffect
// 子组件的data props修改为:
<FyTable
    columnDef={columnDef_FilterCustomer}
    data={data_get_filterCustomer?.data || {}}
    columnDataType={columnType_FilterCustomer}
    resetRowSelection={resetRowSelection}
    handleSelectedRow={handleSelectedRow}
/>

这减少了一次状态更新,避免了tbData引用变化带来的重渲染。

3. 确保静态props引用稳定

确认columnDef_FilterCustomer和columnType_FilterCustomer是模块中静态定义的(而非动态生成),比如:

// ColumnDef.js 正确写法
export const columnDef_FilterCustomer = [
    { field: 'custNo', headerName: 'Customer No' },
    // 其他列定义
];

如果它们是动态生成的(比如函数返回新数组),请用useMemo包裹以稳定引用:

// 在TableCustomer组件中
const columnDef = useMemo(() => columnDef_FilterCustomer(), []);
const columnDataType = useMemo(() => columnType_FilterCustomer(), []);
优化效果验证

修改后,输入字符时父组件仍会重渲染,但传给子组件的所有props引用都保持稳定,React.memo会判定props未变化,阻止子组件不必要的重渲染,从而解决卡顿问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 14:39:53