Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple filters with React Hook - Chaining function

Hello I have created a search bar with a multipl filter, it works but the functions are too dependent on each other. The problem here is that the functions are handling multiple cases. would it be possible to lighten each function by chaining them and how ? I don't really get chaining method. thanks

import React, { useState, useEffect } from "react";
import Search from "./Search";
import Anime from "./Anime";
import "./App.css";

const KIJAN_API_URL = "https://api.jikan.moe/v3/top/anime/1/upcoming";
const App = () => {
  const [animes, setAnimes] = useState([]);
  const [sortedAnimes, setSortedAnimes] = useState([]);
  const [searchValue, setSearchValue] = useState("")
  const [filterByType, setFilterByType] = useState("");
  const [filterByYear, setFilterByYear] = useState("");

  useEffect(() => {
    fetch(KIJAN_API_URL)
      .then(response => {
        if (response.ok) {
          return response.json();
        } else {
          throw new Error("Something went wrong");
        }
      })
      .then(jsonResponse => {
        setAnimes(jsonResponse.top);
      })
      .catch(error => {
        console.log(error);
      });
  }, []);

  useEffect(() => {

    const callFilterByType = result => {
      if (filterByType === "") {
        callFilterByYear(result);
        console.log(result);
      } else {
        result = result.filter(anime => anime.type === filterByType);
        callFilterByYear(result);
        console.log(result);
      }
    };

    const callFilterByYear = result => {
      if (filterByYear === "") {
        setSortedAnimes(result);
      } else {
        const regex = new RegExp(`${filterByYear}`, "gi");
        result = result.filter(anime => regex.test(anime.start_date));
        setSortedAnimes(result);
        console.log(result);
      }
    };

    if (searchValue === "") {
      callFilterByType(animes);
    } else {
      const regex = new RegExp(`${searchValue}`, "gi");
      console.log("search : ", searchValue);
      const result = animes.filter(anime => regex.test(anime.title));
      callFilterByType(result);
      console.log(result);
    }


  }, [searchValue, animes, filterByType, filterByYear]);

  return (
    <div className="App">
      <Search
        searchValue={searchValue}
        setSearchValue={setSearchValue}
        filterByType={filterByType}
        setFilterByType={setFilterByType}
        filterByYear={filterByYear}
        setFilterByYear={setFilterByYear}
      />
      {sortedAnimes.length > 0 ? (
        sortedAnimes.map((anime, index) => {
          return <Anime key={index} anime={anime} />;
        })
      ) : (
        <span>Aucune correspondance</span>
      )}
    </div>
  );
};

export default App;
like image 228
ArBabacar_ Avatar asked Sep 12 '25 07:09

ArBabacar_


1 Answers

SandBox Sample You can do first round of simplification like this:

useEffect(() => {
    let result = [...animes];

    if(searchValue) {
      const searchRegex = new RegExp(`${searchValue}`, "gi");
      result = result.filter(anime => searchRegex.test(anime.title));      
    }

    if(filterByType) {
      result = result.filter(anime => anime.type === filterByType);      
    }

    if(filterByYear) {
      const yearRegex = new RegExp(`${filterByYear}`, "gi");
      result = result.filter(anime => yearRegex.test(anime.start_date));
    }
    setSortedAnimes(result);

}, [searchValue, animes, filterByType, filterByYear]);

It can be reduced to more compact form, like:

useEffect(() => {
    const searchRegex = searchValue && new RegExp(`${searchValue}`, "gi");
    const yearRegex = filterByYear && new RegExp(`${filterByYear}`, "gi");
    const result = animes.filter(anime => 
      (!searchRegex || searchRegex.test(anime.title)) &&
      (!filterByType || anime.type === filterByType)) &&
      (!yearRegex || yearRegex.test(anime.start_date))
    )
    setSortedAnimes(result);
}, [searchValue, animes, filterByType, filterByYear]);

More idiomatic way would be use use momoisation hook. i.e. Remove sortedAnimes as state and

const sortedAnimes = useMemo(() => {
    const searchRegex = searchValue && new RegExp(`${searchValue}`, "gi");
    const yearRegex = filterByYear && new RegExp(`${filterByYear}`, "gi");
    return animes.filter(anime => 
      (!searchRegex || searchRegex.test(anime.title)) &&
      (!filterByType || anime.type === filterByType)) &&
      (!yearRegex || yearRegex.test(anime.start_date))
    )
}, [searchValue, animes, filterByType, filterByYear]);
like image 123
ckedar Avatar answered Sep 14 '25 22:09

ckedar