Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React - adding search to a table, correct way?

I added a search function for my table in React to filter out items fetched from an external webservice. Since I don't want to call the API every time you search for project I figured I'd assign the data retrieved to two different useState hooks.

One to hold the complete dataset and the other to contain the filtered items based on the search.

Could I write cleaner code without using 2 hooks? Any side effects of the way the code is handling this?

Any input is appreciated.

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import Table from '@mui/material/Table';
import TableHead from '@mui/material/TableHead';
import TableBody from '@mui/material/TableBody';
import TableRow from '@mui/material/TableRow';
import TableCell from '@mui/material/TableCell';
import DeleteIcon from '@mui/icons-material/Delete';
import TextField from '@mui/material/TextField';

export default function ShowProject() {
    const [data, setData] = useState([]);
    const [filter, setFilter] = useState([])

    useEffect(() => {
        const fetchData = async () => {
            const result = await axios(
                'http://127.0.0.1:5000/pr'
            );
            setData(result.data);
            setFilter(result.data);
        }
        fetchData()
        
    }, []);

    const requestSearch = (searchedVal) => {
        const filteredRows = data.filter((row) => {
            return row.customer.toString().toLowerCase().includes(searchedVal.toString().toLowerCase());
        });
        if (searchedVal.length < 1) {
            setFilter(data)
        }
        else {
            setFilter(filteredRows)
        }
      };
    
    return (
        <div>
            <div>
                <TextField onChange={(e) => requestSearch(e.target.value)} />
                <Table>
                    <TableHead>
                        <TableRow>
                            <TableCell>Project</TableCell>
                            <TableCell>Code</TableCell>
                            <TableCell>Customer</TableCell>
                            <TableCell></TableCell>
                        </TableRow>
                    </TableHead>
                    <TableBody>
                        {filter.map(item => (
                            <TableRow key={item.db_id}>
                                <TableCell>{item.project_name}</TableCell>
                                <TableCell>{item.project_code}</TableCell>
                                <TableCell>{item.customer}</TableCell>
                                <TableCell><DeleteIcon /></TableCell>
                            </TableRow>
                        ))}
                    </TableBody>
                </Table>
            </div>
        </div>
    )
}
like image 912
Alecbalec Avatar asked Nov 07 '25 01:11

Alecbalec


1 Answers

I don't see any particular reason to use the filter state variable. You're scanning data and assigning the filtered result to filter every time your TextField changes, so why not just do the filtering directly in the JSX and instead store the query text as state? More concretely, something like the following:

  const [searchedVal, setSearchedVal] = useState("");

  return (
    <div>
      <div>
        {/* simply set the query text here instead of triggering requestSearch */}
        <TextField onChange={(e) => setSearchedVal(e.target.value)} />
        <Table>
          <TableHead>
            <TableRow>
              <TableCell>Project</TableCell>
              <TableCell>Code</TableCell>
              <TableCell>Customer</TableCell>
              <TableCell></TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {data
              .filter((row) =>
                // note that I've incorporated the searchedVal length check here
                !searchedVal.length || row.customer
                  .toString()
                  .toLowerCase()
                  .includes(searchedVal.toString().toLowerCase()) 
              )
              .map((item) => (
                <TableRow key={item.db_id}>
                  <TableCell>{item.project_name}</TableCell>
                  <TableCell>{item.project_code}</TableCell>
                  <TableCell>{item.customer}</TableCell>
                  <TableCell>
                    <DeleteIcon />
                  </TableCell>
                </TableRow>
              ))}
          </TableBody>
        </Table>
      </div>
    </div>
  );
like image 94
thisisrandy Avatar answered Nov 09 '25 17:11

thisisrandy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!