使用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

