In today's article we are going to create a basic search logic to filter the data that is being rendered in a table, list or other such component.
In the past I taught how to do a search using a similar mechanism with debounce, basically in the article we did the search for certain "terms" in an external api and then the search results were rendered in a list.
Introduction
From what I've seen on the internet, the simplest and fastest approach is to filter just a small number of properties/attributes. However I find this approach very limited and many times we need to search for lots of properties.
So the idea of today's article is to have an array of objects and when we have a search term we run all these objects and all the properties of these objects to compare their values and finally return the data.
Prerequisites
Before going further, you need:
- Node
- NPM
- React
In addition, you are expected to have basic knowledge of these technologies.
Getting Started
Setup Project
First let's create our project:
npm create vite@latest basic-search -- --template react
cd basic-search
To facilitate the creation of today's article we are going to install a library UI:
npm install @nextui-org/react
Now in the main.tsx
file we add the UI library provider:
// @/src/main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import { NextUIProvider } from "@nextui-org/react";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root")).render(
<NextUIProvider>
<App />
</NextUIProvider>
);
The next step is to create the file with the data that we are going to work with:
// @/src/assets/data.js
export const columns = [
{
key: "name",
label: "NAME",
},
{
key: "role",
label: "ROLE",
},
{
key: "age",
label: "AGE",
},
];
export const rows = [
{
key: "1",
firstName: "Tony",
lastName: "Reichert",
role: "Developer",
age: "35",
},
{
key: "2",
firstName: "Zoey",
lastName: "Lang",
role: "Designer",
age: "22",
},
{
key: "3",
firstName: "Jane",
lastName: "Fisher",
role: "CEO",
age: "29",
},
{
key: "4",
firstName: "William",
lastName: "Howard",
role: "Designer",
age: "27",
},
];
As you may have seen, we have two arrays in the data.js
file in which we have the data of the columns of the table as well as the data of the rows.
With all this ready we can finally start working on the App.jsx
where today's example will be made. First of all we need to do the following imports:
// @/src/App.jsx
import React, { useMemo, useState } from "react";
import { Container, Input, Spacer, Table } from "@nextui-org/react";
import { columns, rows } from "./assets/data";
const App = () => {
// ...
};
export default App;
The next step will be to create the state in which the search term will be stored:
// @/src/App.jsx
import React, { useMemo, useState } from "react";
import { Container, Input, Spacer, Table } from "@nextui-org/react";
import { columns, rows } from "./assets/data";
const App = () => {
const [searchTerm, setSearchTerm] = useState("");
// ...
};
export default App;
Now we can start working on the search logic. To start we have to check if we have a search term and if we don't we will return the rows data. Then, if the rows have data, we can create the search logic.
As you well know, the search term is the value we want to use to filter the table, however we need to know which properties/attributes we want to do this search on. Similar to this:
// @/src/App.jsx
// ...
const App = () => {
const [searchTerm, setSearchTerm] = useState("");
const filteredRows = useMemo(() => {
if (!searchTerm) return rows;
if (rows.length > 0) {
const attributes = Object.keys(rows[0]);
const list = [];
// ...
return list;
}
return [];
}, [searchTerm, rows]);
// ...
};
export default App;
Now that we have the attributes, you can now loop through each of the objects in the array (rows) and in each object we can search for the value of each of the properties/attributes.
First of all we have to ensure that we search for the value of the key, which would match the id. It's not something that's supposed to be filtered out.
If the attribute value is not undefined and it has a value similar to the search term, we can search for the correct object and then add it to the list array so that it is later returned.
// @/src/App.jsx
// ...
const App = () => {
const [searchTerm, setSearchTerm] = useState("");
const filteredRows = useMemo(() => {
if (!searchTerm) return rows;
if (rows.length > 0) {
const attributes = Object.keys(rows[0]);
const list = [];
for (const current of rows) {
for (const attribute of attributes) {
if (attribute === "key") {
continue;
}
const value = current[attribute];
if (value && value.toLowerCase() === searchTerm.toLowerCase()) {
const found = rows.find((row) => row.key === current.key);
if (found) {
list.push(found);
}
}
}
}
return list;
}
return [];
}, [searchTerm, rows]);
// ...
};
export default App;
With the logic created we can now work in our JSX, not forgetting that the data of the table rows that must be rendered is the filteredRows
. Like this:
// @/src/App.jsx
import React, { useMemo, useState } from "react";
import { Container, Input, Spacer, Table } from "@nextui-org/react";
import { columns, rows } from "./assets/data";
const App = () => {
const [searchTerm, setSearchTerm] = useState("");
const filteredRows = useMemo(() => {
if (!searchTerm) return rows;
if (rows.length > 0) {
const attributes = Object.keys(rows[0]);
const list = [];
for (const current of rows) {
for (const attribute of attributes) {
if (attribute === "key") {
continue;
}
const value = current[attribute];
if (value && value.toLowerCase() === searchTerm.toLowerCase()) {
const found = rows.find((row) => row.key === current.key);
if (found) {
list.push(found);
}
}
}
}
return list;
}
return [];
}, [searchTerm, rows]);
return (
<Container>
<Spacer y={4} />
<Input
size="lg"
bordered
clearable
placeholder="Search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<Spacer y={2} />
<Table>
<Table.Header>
{columns.map((column) => (
<Table.Column key={column.key}>{column.label}</Table.Column>
))}
</Table.Header>
<Table.Body>
{filteredRows.map((row) => (
<Table.Row key={row.key}>
<Table.Cell>{row.firstName + " " + row.lastName}</Table.Cell>
<Table.Cell>{row.role}</Table.Cell>
<Table.Cell>{row.age}</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
</Container>
);
};
export default App;
Conclusion
As always, I hope you enjoyed this article and that it was useful to you. If you have seen any errors in the article, please let me know in the comments so that I can correct them.
Before I finish, I will share with you this link to the github repository with the project code for this article.
Top comments (0)