foreigninstuction
foreigninstuction

Reputation: 105

How to Optimize React array multiple values filtering

I have a list of events that i need to filter using three values (event name, event country and event City):

Here are the states for the inputs :

 //set up search inputs (event name, event city, event country)
    const [searchedEName, setSearchedEName] = useState("");
    const [searchedECountry, setSearchedECountry] = useState("");
    const [searchedECity, setSearchedECity] = useState("");

the inputs :

<div >
                            <input type="text" value={searchedEName} name="name" onChange={(e) => setSearchedEName(e.target.value)} />
                            <label>Event Name</label>
                        </div>
                        <div>
                            <input type="text" value={searchedECountry} name="country"   onChange={(e) => setSearchedECountry(e.target.value)} />
                            <label>Country</label>
                        </div>

                        <div >
                            <input type="text" value={searchedECity} name="city" 
onChange={(e) => setSearchedECity(e.target.value)}  />
                            <label>City</label>
                        </div>

and finally the filtering and mapping of the array

 <motion.div className="events" >
                    {availableEvents.filter((event) => {
                       
                        if (searchedEName == "" && searchedECountry == "" && searchedECity == "") {
                            return event;
                        }
                        
                        else if (event.event.eventName.toLowerCase().includes(searchedEName.toLowerCase()) && searchedECity == "" && searchedECountry == "") {
                            return event;
                        }
                        else if (event.event.country.toLowerCase().includes(searchedECountry.toLowerCase()) && searchedECity == "" && searchedEName == "") {
                            return event;
                        }
                        else if (event.event.city.toLowerCase().includes(searchedECity.toLowerCase()) && searchedEName == "" && searchedECountry == "") {
                            return event;
                        }

                        else if (event.event.eventName.toLowerCase().includes(searchedEName.toLowerCase()) && event.event.city.toLowerCase().includes(searchedECity.toLowerCase()) && searchedECountry == "") {
                            return event;
                        }
                       
                        else if (event.event.eventName.toLowerCase().includes(searchedEName.toLowerCase()) && event.event.country.toLowerCase().includes(searchedECountry.toLowerCase()) && searchedECity == "") {
                            return event;
                        }
                        else if (event.event.city.toLowerCase().includes(searchedECity.toLowerCase()) && event.event.country.toLowerCase().includes(searchedECountry.toLowerCase()) && searchedEName == "") {
                            return event;
                        }
                       
                        else if (event.event.eventName.toLowerCase().includes(searchedEName.toLowerCase()) && event.event.country.toLowerCase().includes(searchedECountry.toLowerCase()) && event.event.city.toLowerCase().includes(searchedECity.toLowerCase())) {
                            return event;
                        }
                    }).map((event) => {
                        return <Event key={event.event.id} event={event.event} />
                    })}
                </motion.div>

Now this does work but i can't help but think that there should be a better way to do the filtering without coding every single possible scenario.

Please Can you help me find a solution to this.

Upvotes: 1

Views: 509

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370769

Any string also contains the empty string. So, for example, assuming that event.event.eventName will always exist as a string, this:

if (searchedEName == "" && searchedECountry == "" && searchedECity == "") {
  return event;
} else if (event.event.eventName.toLowerCase().includes(searchedEName.toLowerCase()) && searchedECity == "" && searchedECountry == "") {
  return event;
}

is equivalent to

if (event.event.eventName.toLowerCase().includes(searchedEName.toLowerCase()) && searchedECity == "" && searchedECountry == "") {
  return event;
}

Continue this pattern, and you'll see that all of your branches are superfluous, except the one at the end - which can be made much more DRY with a helper function:

const contains = (event, prop, against) => event.event[prop].toLowerCase().includes(against.toLowerCase());
{availableEvents.filter(event => (
  contains(event, 'eventName', searchedEName) &&
  contains(event, 'country', searchedECountry) &&
  contains(event, 'city', searchedECity)
))}

Upvotes: 1

Related Questions