The textInput component goes unchecked on every key I press, making it completely useless. I tried with useMemo, with a custom component. Nothing. This still doesn’t work.
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 { IconSearch, IconX } from '@tabler/icons-react';
const Customers = (): any => {
const dispatch = useDispatch();
const [customers, setCustomers] = useState([] as any);
const [customersNotEmpty, setCustomersNotEmpty] = useState(false as boolean);
useEffect(() => {
dispatch(setPageTitle('Customers'));
}, []);
useEffect(() => {
getCustomers()
.then((response) => setCustomers(response.data))
.then(() => setCustomersNotEmpty(true));
}, [customersNotEmpty]);
const [filter, setFilter] = useState('');
const filteredData = customers?.filter((item: any) =>
item.name.toLowerCase().includes(filter.toLowerCase())
);
const NameColumnHeader = () => (
<div className="flex items-center justify-between">
<span className="mr-2">Name</span>
<TextInput
className=""
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>
);
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 /> },
{ 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;
I don’t know what to do. Both TextInput and DataTable components are from Mantine.
How can I get a simple, working, table with filtering?
>Solution :
Your code above defines NameColumnHeader inside a component named Customers.
A component is a JavaScript function. When a component "renders", you are simply running that JavaScript function.
You have defined a function (let’s call it B()) inside of a function (A()). Every single time that A() is run, it will recreate B(). It is not the same B() as in the previous run.
In React terms: you have defined a component <B> inside of the code of component <A>. Each time that <A> renders, you get a new component called <B>.
Do not define components inside of components. 99.47% of the time you will not be happy with the results.