Mantine DataTable中TextInput失焦问题及表格过滤实现求助
解决Mantine DataTable中TextInput按键失焦问题
问题根源
你在Customers组件内部定义了NameColumnHeader组件,每次输入框触发filter状态更新时,Customers组件会重新渲染,NameColumnHeader会被重新创建为全新的组件实例。DataTable检测到表头元素变化后,会卸载原输入框并重建,直接导致输入框失焦。
另外你的数据获取逻辑存在无限循环问题:useEffect依赖customersNotEmpty,获取数据后设置该状态为true,会再次触发这个useEffect重复请求数据。
修复代码
import React, { useState, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { Link } from 'react-router-dom'; import { setPageTitle } from '../store/themeConfigSlice'; import { getCustomers } from '../services/customerService'; import { DataTable, ActionIcon, TextInput } from 'mantine-datatable'; import { IconX } from '@tabler/icons-react'; // 将表头组件移到外部,通过props传递状态 const NameColumnHeader = ({ filter, setFilter }: { filter: string; setFilter: (value: string) => void }) => ( <div className="flex items-center justify-between"> <span className="mr-2">Name</span> <TextInput label="" placeholder="Search by Name..." value={filter} onChange={(e) => setFilter(e.currentTarget.value)} rightSection={ filter && ( <ActionIcon size="sm" variant="transparent" c="dimmed" onClick={() => setFilter('')} > <IconX size={14} /> </ActionIcon> ) } /> </div> ); const Customers = (): JSX.Element => { const dispatch = useDispatch(); const [customers, setCustomers] = useState([] as any); const [filter, setFilter] = useState(''); useEffect(() => { dispatch(setPageTitle('Customers')); }, []); // 修正数据获取逻辑:仅在组件挂载时请求一次 useEffect(() => { getCustomers() .then((response) => setCustomers(response.data)); }, []); const filteredData = customers?.filter((item: any) => item.name.toLowerCase().includes(filter.toLowerCase()) ); return ( <div> <ul className="flex space-x-2 rtl:space-x-reverse"> <li> <Link to="/" className="text-primary hover:underline"> Dashboard </Link> </li> <li className="before:content-['/'] ltr:before:mr-2 rtl:before:ml-2"> <span>Customers</span> </li> </ul> <div className="flex flex-col xl:flex-row gap-5 relative mt-5"> <DataTable noRecordsText="No results match your search query" highlightOnHover className="whitespace-nowrap table-hover" records={filteredData} columns={[ { accessor: 'client_id', title: '#' }, // 传递状态给外部组件 { accessor: 'name', title: <NameColumnHeader filter={filter} setFilter={setFilter} /> }, { accessor: 'code', title: 'Code' }, { accessor: 'address_city', title: 'City' }, { accessor: 'address_province', title: 'Province' }, { accessor: 'country', title: 'Country' }, { accessor: 'vat_number', title: 'VAT' }, { accessor: 'id', title: 'ID' }, ]} totalRecords={customers?.length} recordsPerPage={10} page={1} onPageChange={() => null} recordsPerPageOptions={[0]} onRecordsPerPageChange={() => null} sortStatus={undefined} onSortStatusChange={undefined} minHeight={200} paginationText={({ from, to, totalRecords }) => `Showing ${from} to ${to} of ${totalRecords} entries` } /> </div> </div> ); }; export default Customers;
关键修改点
- 提取表头组件:把
NameColumnHeader移到Customers组件外部,避免每次渲染时创建新组件实例,保证输入框的DOM稳定性。 - 修正数据请求逻辑:移除
customersNotEmpty状态和对应的依赖,改为仅在组件挂载时请求一次数据,解决无限循环问题。 - 传递状态props:通过props将
filter和setFilter传递给NameColumnHeader,保持状态控制的正确性。
内容的提问来源于stack exchange,提问作者user74747
相关产品推荐
相关产品推荐

