简体   繁体   中英

render a list using map but filter base on user's query in frontend

I want to achieve this result: https://resepi-khairulaming.vercel.app/

It's easy to just fetch the result from backend by passing the query, but how about doing the filter on the client side? do I need to hold 2 states, eg.

const [data, setData] = useState() // setData from api source on onload const [filteredData setFilteredData] = useState(data)

one is the original source and the another is the filtered source? Because the user can clear the query and I have to restore unfiltered data.

is there any better solution than this?

You definitely need one state for the semi-persistent API results. For the filtered data to be rendered, having another state like you're thinking is a common option - there's nothing wrong with that.

Another option is to filter the API data before rendering, without an additional state.

return (
  <div>
    {
      data
        .filter(obj => obj.name.toLowerCase().includes(inputValue.toLowerCase())
        .map( /* etc */

Another is to memoize the filtered data, with a dependency array of the state from the API and whatever filters it.

const [data, setData] = useState([]);
const filteredData = useMemo(
  () => data.filter(obj => obj.name.toLowerCase().includes(inputValue.toLowerCase())
  [data, inputValue]
);

The inputValue s and .name s used above are just examples - replace with whatever your actual filtering mechanism is.

Instead of setting and restoring the filtered state every time when a user tries to search for a value, memorization can be a possible and better option.

import React, {useState, useMemo} from 'react';

const Home = () => {
    const [data, setData] = useState([]);
    const [searchVal, setSearchVal] = useState('')

    const filteredData = useMemo(() => {
        if (searchVal.trim() === '') {
            return data;
        }
        return data.filter(dataItem => dataItem.name === searchVal);
    }, [data, searchVal])

    // use the filteredData in your list..
}

So you want to optimize the search behaviour.

Here's what I noticed is happening, based on that example you sent and here are some optimization suggestions:

  1. The search is immediately triggered on the keydown or onchange event with no delay which may not be the ideal way of doing it. You want to either throttle or debounce in such a case. Look these terminologies up. They will save you multiple API calls. What they will help do is run the API query, only when the user stops typing for an X amount of time, otherwise don't.
  2. It's an API call to a database. In production, you may want to use ElasticSearch or a search engine which stores indexes in memory.
  3. You could also cache most searched results and first hit the cache, if missed, then query database. Options: Redis, Memcached, ElastiCache, ElasticSearch.
  4. Holding the data in a state is not a good option, unless the number of records is less. If it goes into thousands, you wouldn't want to make such an expensive call to your database and then hold that.

Other resources for you to read on: Full-Text Search (That's what this intended behaviour is called)

Suggestion for immediate fix: Make the database call after every onchange (if possible, try to implement debounce to save on API calls, it's easy)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM