React Hook Forms对接React Table自定义组件无限重渲染如何解决?
无限重渲染问题解决方案
问题根源
你的代码触发循环重渲染的核心原因是引用不稳定导致的更新链路循环:
- 父组件使用
watch('user_ids')监听字段,每次user_ids更新都会触发父组件重渲染 - 重渲染时父组件给
UserTable传递的属性、UserTable内部生成的回调函数、衍生数组每次都会生成新的引用,触发BasicTable的更新逻辑 BasicTable更新后又会调用onSelectedRowsChange回调更新user_ids,回到第一步形成死循环
修复步骤
1. 移除冗余的watch调用
你在Controller的render回调中已经可以直接拿到最新的field.value,不需要额外用watch监听字段,避免父组件不必要的重渲染,修改父组件代码:
<Controller control={control} name={fieldName("user_ids")} render={({ field: { value, onChange } }) => ( <UserTable selectedUserIds={value || []} updatePropertySelection={onChange}/> )} />
2. 缓存UserTable内部的不稳定引用
用useCallback包裹事件回调,useMemo包裹衍生的选中值数组,避免每次渲染生成新引用:
import { useCallback, useMemo } from 'react'; // UserTable组件内部 const updatePropertyTableSelection = useCallback((ids) => { const processedIds = extractIds(ids); updatePropertySelection(processedIds); }, [updatePropertySelection, extractIds]); // 按实际情况补全所有依赖项 const selectedUserIdsForTable = useMemo(() => { return convertIdsToTableFormat(selectedUserIds) }, [selectedUserIds, convertIdsToTableFormat]); // 按实际情况补全所有依赖项
3. 缓存表格配置项
BasicTable的columns属性如果定义在组件内部,每次渲染都会生成新的数组引用,触发表格重渲染,建议挪到组件外部或者用useMemo缓存:
// 方案1:挪到组件外部定义(无依赖时首选) const TABLE_COLUMNS = [ { Header: "User Name", accessor: "attributes.name", } ]; // 组件内使用:<BasicTable columns={TABLE_COLUMNS} ... /> // 方案2:组件内用useMemo缓存(有动态依赖时使用) const columns = useMemo(() => [ { Header: "User Name", accessor: "attributes.name", } ], []);
4. 可选:加更新前置校验
如果处理后的id数组和当前选中值完全一致,可以跳过更新,避免不必要的重渲染:
const updatePropertyTableSelection = useCallback((ids) => { const processedIds = extractIds(ids); // 浅比较数组内容,一致则不触发更新 if (processedIds.length === selectedUserIds.length && processedIds.every((id, idx) => id === selectedUserIds[idx])) { return; } updatePropertySelection(processedIds); }, [updatePropertySelection, extractIds, selectedUserIds]);
内容的提问来源于stack exchange,提问作者lost9123193
相关产品推荐
相关产品推荐

