react-table子组件向父组件传选中行数据时触发更新深度超限错误
解决react-table子组件传递选中行到父组件的无限循环问题
问题根源
你遇到的「Maximum update depth exceeded」错误,本质是状态更新触发组件重新渲染,而重新渲染又再次触发状态更新,形成无限循环。常见触发原因有两个:
- 子组件内用
useState冗余存储选中状态,且useEffect依赖项设置不当,导致selectedFlatRows变化→调用setSelectedRows→组件重渲染→selectedFlatRows再次变化→重复触发useEffect。 - 父组件传递的回调函数未用
useCallback包裹,每次父组件渲染都会生成新的函数引用,导致子组件useEffect依赖项变化,触发不必要的更新,进而引发循环。
解决方案
核心思路是去掉子组件内冗余的状态存储,直接将react-table原生的selectedFlatRows通过父组件回调传递,同时确保父组件的回调引用稳定。
步骤1:父组件优化
用useCallback包裹传递给子组件的回调函数,保证其引用不会随父组件渲染频繁变化:
import { useState, useCallback } from 'react'; import ChildTable from './ChildTable'; function Parent() { const [selectedRows, setSelectedRows] = useState([]); // 用useCallback包裹,依赖项为空数组,确保引用稳定 const handleRowSelect = useCallback((selectedData) => { setSelectedRows(selectedData); }, []); return ( <div> <ChildTable onRowSelect={handleRowSelect} /> <div>已选中行:{JSON.stringify(selectedRows)}</div> </div> ); }
步骤2:子组件优化
直接监听react-table的selectedFlatRows变化,调用父组件的回调,无需额外用useState存储:
import { useTable, useRowSelect } from 'react-table'; import { useEffect } from 'react'; function ChildTable({ columns, data, onRowSelect }) { const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, selectedFlatRows, } = useTable( { columns, data }, useRowSelect, (hooks) => { // 添加入选列 hooks.visibleColumns.push((cols) => [ { id: 'selection', Header: ({ getToggleAllRowsSelectedProps }) => ( <input type="checkbox" {...getToggleAllRowsSelectedProps()} /> ), Cell: ({ row }) => ( <input type="checkbox" {...row.getToggleRowSelectedProps()} /> ), }, ...cols, ]); } ); // 监听选中行变化,传递给父组件 useEffect(() => { // 提取选中行的原始数据(可根据需求调整) const selectedData = selectedFlatRows.map(row => row.original); onRowSelect(selectedData); }, [selectedFlatRows, onRowSelect]); // 依赖项包含稳定的回调函数 // 渲染表格 return ( <table {...getTableProps()}> <thead> {headerGroups.map(headerGroup => ( <tr {...headerGroup.getHeaderGroupProps()}> {headerGroup.headers.map(col => ( <th {...col.getHeaderProps()}>{col.render('Header')}</th> ))} </tr> ))} </thead> <tbody {...getTableBodyProps()}> {rows.map(row => { prepareRow(row); return ( <tr {...row.getRowProps()}> {row.cells.map(cell => ( <td {...cell.getCellProps()}>{cell.render('Cell')}</td> ))} </tr> ); })} </tbody> </table> ); }
额外注意事项
- 如果必须在子组件内存储选中状态,一定要确保
useEffect的依赖项不会触发循环:比如不要将子组件的selectedRows作为useEffect的依赖,同时避免父组件将selectedRows回传给子组件引发二次更新。 - 若仍出现循环,可检查
selectedFlatRows是否在每次渲染时都生成新的引用(react-table的selectedFlatRows是稳定的,除非数据或选中状态真的变化),必要时可通过useMemo对选中数据做浅比较优化。
内容的提问来源于stack exchange,提问作者Nitin T
相关产品推荐
相关产品推荐

