【问题标题】:Multiple filters with React Hook - Chaining function带有 React Hook 的多个过滤器 - 链接功能
【发布时间】:2019-09-19 09:02:14
【问题描述】:

您好,我创建了一个带有多重过滤器的搜索栏,它可以工作,但功能过于依赖彼此。这里的问题是这些函数正在处理多种情况。 是否可以通过链接它们来减轻每个功能以及如何减轻?我真的没有得到链接方法。 谢谢

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;

【问题讨论】:

  • 参见this other question,只需将逻辑的每个部分分离成自己的useEffect
  • 您好@Alvaro 感谢您的洞察力,但我不认为我无法管理具有 3 种不同 useEffect 的数据,即使它们监控不同的输入。主要问题是函数必须通过协同工作或单独工作来给出结果。如果我在同一个数组上工作,UseEffect 将设置值未定义,因此我不能在其他必须使用该值的 useEffects 中使用它们
  • @ArBabacar_ 也许重构代码会有所帮助。使用useStateuseEffect。很难确切地说出是怎么回事,因为我们不知道searchValue, animes, setSortedAnimes 来自哪里。
  • 抱歉@Alvaro searchValue 来自我的 SearchBar 组件,animes 来自 API,并且 setSortedAnimes 在您应用过滤器时更新了数组动画
  • 你能分享完整的组件吗?我问是因为我不确定setSortedAnimes 是否属于useState,或者它如何修改获取的动画。

标签: reactjs react-hooks chaining


【解决方案1】:

SandBox Sample 您可以像这样进行第一轮简化:

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]);

它可以简化为更紧凑的形式,例如:

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]);

更惯用的方法是使用 momoisation 钩子。即删除 sortedAnimes 作为状态和

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]);

【讨论】:

  • 以上useMemo 语句用于替换其他状态语句之后的[sortedAnimes, setSortedAnimes] = useState([]) 语句。使用useMemo,您将不需要在原始代码中使用第二个效果(即进行过滤)。
  • 如果您能提供一些在线沙箱中的示例工作代码,例如codesandbox、codepen等,那将很容易检查。
  • 它更干净,知道我会更清洁,我会告诉你谢谢
【解决方案2】:

试试这个

如果你在 jsx 中使用 filter 方法,那么你试试这个方法。

让我简单介绍一下, 将 userInfo 视为一个包含名称、电子邮件、位置等字段的对象。因此,如果您希望您的过滤器方法根据这些字段值提供搜索结果,那么您可以在 jsx 中使用类似这样的东西。

    {userInfo.filter((user) => (
                                    
                        user.name.toLowerCase().includes(cloneSearchTerm)
                        ||
                        user.email.toLowerCase().includes(cloneSearchTerm)
                        ||
                        user.location.toLowerCase().includes(cloneSearchTerm)
                    )
    
                    ).map((user, idx) => (
                        <div key={idx}>
                                <span>{user.name}</span>
                                <span>{user.email}</span>
                                <span>{user.location}</span>
                        </div>

                    ))}

【讨论】:

    猜你喜欢
    • 2020-04-19
    • 2020-10-28
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 2016-06-15
    相关资源
    最近更新 更多