Reputation: 121
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?
Upvotes: 0
Views: 534
Reputation: 1204
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..
}
Upvotes: 0
Reputation: 179
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:
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.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)
Upvotes: 0
Reputation: 370809
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.
Upvotes: 1