skip to Main Content

In my component JobList I am displaying a list of Job cards which is loaded in useEffect The job list is stored in the state. It works fine if I am displaying the list as is. However if I am filtering jobs based on user search, the state is reset and useEffect is not triggered which in turn does not load the job List resulting into error.

Snippet:

export default function JobList() {
  const [jobs, setjobs] = useState(initialValues);
  const [query, setQuery] = useState("");

  useEffect(() => {
    // loading the jobs from backend
    const fetchJobs = async () => {
      const jobList = await jobServices.getJobsList();
      setjobs(jobList);
    };
    fetchJobs().catch((error) => handleError(error));
  }, []);

  const keys = [
    "vehicle",
    "customer_mobile"
  ];
  
  // this function is to filter jobs based on user search
  const filteredJobs = (jobs) => {
    return jobs.filter((job) => keys.some((key) => job[key].includes(query)));
  };

 return (
    <>
      <Container>
        <TextField
          label="Search Jobs"
          type="search"
          onChange={(e) => setQuery(e.target.value)}
        />
      </Container>
      <Container>
        <Grid container spacing={6}>
          {filteredJobs(jobs).map((job) => (
            <Grid key={job.id} item xs={4}>
              <JobCard job={job} handleError={handleError} key={job.id} />
            </Grid>
          ))}
        </Grid>
      </Container>
    </>
  );
}

This code works for initial load but after any user action the jobs state is reset and useEffect is not triggered. It works absolutely fine it I do not filter jobs.

If I do (no filtering):

<Grid container spacing={6}>
              {jobs.map((job) => (
                <Grid key={job.id} item xs={4}>
                  <JobCard job={job} handleError={handleError} key={job.id} />
                </Grid>
              ))}
            </Grid>

Instead of (filtering):

<Grid container spacing={6}>
              {filteredJobs(jobs).map((job) => (
                <Grid key={job.id} item xs={4}>
                  <JobCard job={job} handleError={handleError} key={job.id} />
                </Grid>
              ))}
            </Grid>

It works as expected.

I am thinking it is due to the way I am calling filteredJobs function while rendering.

Any suggestions will be appreciated!

2

Answers


  1. To fix this, you can improve the filteredJobs function to ensure it shows all jobs when the search bar is empty or the search term doesn’t match any jobs.

     
    const filteredJobs = (jobs) => {
      if (!query) { // Check if the query is empty
        return jobs; // Return all jobs if the query is empty
      }
    
      return jobs.filter((job) => keys.some((key) => job[key]?.toString().includes(query)));
    };
    
    Login or Signup to reply.
  2. try these modifications:

    1. We are using the hook useMemo to change filteredJobs when just jobs or query changes
    2. keys can go outside the component to prevent rerender of the const
    3. create a function to handleSearch
    
    import { useState, useEffect, useMemo } from "react";
    
    const keys = ["vehicle", "customer_mobile"];
    
    export default function JobList() {
      const [jobs, setJobs] = useState(initialValues);
      //my suggestion is to use a hook to debounce the search query
      const [query, setQuery] = useState("");
      useEffect(() => {
        const fetchJobs = async () => {
          const jobList = await jobServices.getJobsList();
          setJobs(jobList);
        };
        fetchJobs().catch(handleError);
      }, []);
    
      const filteredJobsMemoized = useMemo(()=>{
          return jobs.filter((job) =>
        keys.some((key) => job[key].includes(query))
      );
      },[jobs,query]);
    
      function handleSearch(event) {
        setQuery(event.target.value);
      }
    
      return (
        <>
          <Container>
            <TextField label="Search Jobs" type="search" onChange={handleSearch} />
          </Container>
          <Container>
            <Grid container spacing={6}>
              {filteredJobsMemoized.map((job) => (
                <Grid key={job.id} item xs={4}>
                  <JobCard job={job} handleError={handleError} />
                </Grid>
              ))}
            </Grid>
          </Container>
        </>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search