Antd Table搜索清空后无法恢复原始数据问题求助
Antd Table搜索过滤后无法恢复原始数据的问题解决
问题描述
我尝试通过Antd Search组件的onChange事件实现Antd Table的数据过滤功能,输入搜索关键词时过滤正常,但清空搜索内容后无法恢复表格的原始数据,疑似状态未在最新onChange事件后更新。
我参考了两个示例:一个是将数据映射为普通元素而非Antd Table的实现,另一个是类组件版本的实现,但难以将其逻辑适配到我的函数组件中,尤其对其中的map函数逻辑存疑。此外,使用原生HTML Table结合map函数的相同实现未出现该问题。
相关代码:
export default function DriversModal({ isVisible, handleClose }) { const initialUserData = [ { type: 2, user: { name: 'TestName1', username: 'name1@email.com'}, phone: '(123) 456-1111', ops: 37 }, { type: 1, user: { name: 'TestName2', username: 'name2@email.com'}, phone: '(123) 456-2222', ops: 16 }, { type: 2, user: { name: 'TestName3', username: 'name3@email.com'}, phone: '(123) 456-3333', ops: 4 }, { type: 1, user: { name: 'TestName4', username: 'name4@email.com'}, phone: '(123) 456-4444', ops: 52 } ] const columns = [ { title: 'Name', dataIndex: 'user', render: (user) => ( <> <div className="list-modal-cell-text-primary">{user.name}</div> <div className="list-modal-cell-text-secondary">{user.username}</div> </> ), width: 320, key: '1', }, { title: 'Phone', dataIndex: 'phone', width: 144, key: '2', }, { title: 'Ops', dataIndex: 'ops', key: '3', }, ]; const [users, setUsers] = useState(initialUserData); const [query, setQuery] = useState(''); const handleChange = (e) => { setQuery(e.target.value); } useEffect(() => { setUsers(users.filter(item => item.user.name.toLowerCase().includes(query.toLowerCase()) || item.user.username.toLowerCase().includes(query.toLowerCase()) )) }, [query, users]) return ( <Modal title={<DriversModalHeader handleChange={handleChange} handleSort={handleSort} query={query} />} bodyStyle={{ height: '264px'}} visible={isVisible} closable={false} destroyOnClose={true} footer={[ <Button onClick={handleClose} > Close </Button> ]} > <Table dataSource={users} columns={columns} pagination={false} scroll={{ y: 240, }} row /> </Modal> ) }
DriversModalHeader代码:
export default function DriversModalHeader({ handleChange, handleSort, query }) { const menu = ( <Menu> <Menu.Item key="availability" onClick={handleSort}>Sort by availability</Menu.Item> <Menu.Item key="alphabetic" onClick={handleSort}>Sort alphabetically</Menu.Item> </Menu> ) return ( <div className="list-modal-header"> <div className="title"> <div className="title"> Drivers </div> </div> <div className="elements"> <div className="list-modal-input-with-button"> <Input.Search value={query} placeholder="Search" onChange={handleChange} /> <span className="icon"> <Icon component={Search} style={{fontSize: '16px'}} /> </span> </div> <div className="list-modal-dropdown"> <StateSelect /> </div> <div> <Dropdown.Button placement="bottomRight" className="union" overlay={menu} trigger={['click']} icon={<Icon component={Union} style={{fontSize: '24px'}}/>} > </Dropdown.Button> </div> </div> </div> ); };
问题分析
核心问题是你用过滤后的数据覆盖了原始数据状态:每次useEffect触发时,你基于当前的users状态进行过滤,而users在第一次过滤后已经变成了数据子集。当清空搜索框时,query为空,此时你用已经被过滤过的users执行filter(空条件下会返回当前users),自然无法恢复到最初的完整数据。
另外,useEffect依赖数组中包含users会导致不必要的重复触发,进一步加剧状态混乱。
解决方案
方案1:保留原始数据,每次过滤基于原始数据
将原始数据作为常量保存,每次过滤都从原始数据出发,而非当前的users状态:
export default function DriversModal({ isVisible, handleClose }) { // 原始数据作为常量,不修改 const initialUserData = [ { type: 2, user: { name: 'TestName1', username: 'name1@email.com'}, phone: '(123) 456-1111', ops: 37 }, { type: 1, user: { name: 'TestName2', username: 'name2@email.com'}, phone: '(123) 456-2222', ops: 16 }, { type: 2, user: { name: 'TestName3', username: 'name3@email.com'}, phone: '(123) 456-3333', ops: 4 }, { type: 1, user: { name: 'TestName4', username: 'name4@email.com'}, phone: '(123) 456-4444', ops: 52 } ] const columns = [ { title: 'Name', dataIndex: 'user', render: (user) => ( <> <div className="list-modal-cell-text-primary">{user.name}</div> <div className="list-modal-cell-text-secondary">{user.username}</div> </> ), width: 320, key: '1', }, { title: 'Phone', dataIndex: 'phone', width: 144, key: '2', }, { title: 'Ops', dataIndex: 'ops', key: '3', }, ]; const [users, setUsers] = useState(initialUserData); const [query, setQuery] = useState(''); const handleChange = (e) => { setQuery(e.target.value); } useEffect(() => { // 基于原始数据过滤,而非当前users状态 const filtered = initialUserData.filter(item => item.user.name.toLowerCase().includes(query.toLowerCase()) || item.user.username.toLowerCase().includes(query.toLowerCase()) ); setUsers(filtered); }, [query]) // 移除users依赖,避免重复触发 return ( <Modal title={<DriversModalHeader handleChange={handleChange} query={query} />} bodyStyle={{ height: '264px'}} visible={isVisible} closable={false} destroyOnClose={true} footer={[ <Button onClick={handleClose}>Close</Button> ]} > <Table dataSource={users} columns={columns} pagination={false} scroll={{ y: 240 }} /> </Modal> ) }
方案2:使用衍生状态,直接计算过滤结果(推荐)
不需要将过滤后的数据存入状态,直接在渲染时基于原始数据和query计算结果,避免状态不同步问题:
export default function DriversModal({ isVisible, handleClose }) { const initialUserData = [ { type: 2, user: { name: 'TestName1', username: 'name1@email.com'}, phone: '(123) 456-1111', ops: 37 }, { type: 1, user: { name: 'TestName2', username: 'name2@email.com'}, phone: '(123) 456-2222', ops: 16 }, { type: 2, user: { name: 'TestName3', username: 'name3@email.com'}, phone: '(123) 456-3333', ops: 4 }, { type: 1, user: { name: 'TestName4', username: 'name4@email.com'}, phone: '(123) 456-4444', ops: 52 } ] const columns = [ { title: 'Name', dataIndex: 'user', render: (user) => ( <> <div className="list-modal-cell-text-primary">{user.name}</div> <div className="list-modal-cell-text-secondary">{user.username}</div> </> ), width: 320, key: '1', }, { title: 'Phone', dataIndex: 'phone', width: 144, key: '2', }, { title: 'Ops', dataIndex: 'ops', key: '3', }, ]; const [query, setQuery] = useState(''); const handleChange = (e) => { setQuery(e.target.value); } // 直接计算过滤结果,无需存入状态 const filteredUsers = initialUserData.filter(item => item.user.name.toLowerCase().includes(query.toLowerCase()) || item.user.username.toLowerCase().includes(query.toLowerCase()) ); return ( <Modal title={<DriversModalHeader handleChange={handleChange} query={query} />} bodyStyle={{ height: '264px'}} visible={isVisible} closable={false} destroyOnClose={true} footer={[ <Button onClick={handleClose}>Close</Button> ]} > <Table dataSource={filteredUsers} columns={columns} pagination={false} scroll={{ y: 240 }} /> </Modal> ) }
额外说明
- 方案2更简洁,减少了不必要的状态管理,完全避免状态不同步风险。
- 注意移除原代码中
Table组件多余的row属性,避免控制台报错。
内容的提问来源于stack exchange,提问作者jfont
相关产品推荐
相关产品推荐

