使用搜索字段搜索特定节目时出现重复且不相关的标题

问题描述 投票:0回答:1

我正在使用 Jikan API 创建某种动漫画廊,我想要包含的功能之一是能够在画廊中搜索特定的动漫标题。我的问题是我当前的搜索输入字段;尽管指定了节目,它仍会显示您搜索的特定标题以及完全不同节目的几个重复标题。

我遇到的另一个问题是,尽管对获取的显示数据数量设置了限制,但一旦我清除搜索字段,尽管有限制,这些相同的重复项仍将被添加到图库中。

用户输入特定动漫标题时的图库图像

应用程序.js

import './App.css';
import AnimeGallery from './components/AnimeGallery';
import Footer from './components/Footer';
import Header from './components/Header';
import NavFilter from './components/NavFilter';
import { useState, useEffect } from 'react';

function App() {
  const animeApi = 'https://api.jikan.moe/v4/top/anime?type=tv&sfw=true&limit=12&filter=airing';

  const [animeList, setAnimeList] = useState([]);
  const [filteredAnime, setFilteredAnime] = useState([])

  useEffect(() => {
    const fetchAnimeGenre = async () => {
      const result = await fetch(animeApi);
      const data = await result.json();
      setAnimeList(data.data);
      setFilteredAnime(data.data);
    };
    fetchAnimeGenre();
  }, []);


  return (
    <>
      <Header />
      <NavFilter animeList={animeList} setFilteredAnime={setFilteredAnime} />
      <AnimeGallery animeList={filteredAnime} />
      <Footer />
    </>
  );
}

export default App;

NavFilter.js

import '../styles/NavFilter.module.css'
import { useState } from 'react';

const NavFilter = ({ animeList, setFilteredAnime }) => {

    const [searchAnime, setSearchAnime] = useState('');

    const preventReload = (e) => {
        e.preventDefault();
    }

    const handleSearchNav = (e) => {
        const searchTitle = e.target.value;
        setSearchAnime(searchTitle);

        if (searchTitle === '') {
            setFilteredAnime(animeList);
        } else {

            const filteredResults = animeList.filter(anime =>
                anime.title.toLowerCase().includes(searchTitle.toLowerCase())
            );

            setFilteredAnime(filteredResults);
        };
    }



    return (
        <>
            <nav>
                <div className="w-full p-5 shadow-xl">
                    <ul className="flex justify-center tracking-wider text-sm">

                        <li>
                            <form
                                onSubmit={preventReload}
                            >
                                <input
                                    type="text"
                                    className="rounded-md px-8 py-1"
                                    placeholder="Search Anime..."
                                    value={searchAnime}
                                    onChange={handleSearchNav}></input>
                            </form>
                        </li>
                    </ul>
                </div>
            </nav>
        </>
    )
}

export default NavFilter;

AnimeGallery.js

import '../styles/AnimeGallery.module.css';

const AnimeGallery = ({ animeList }) => {

    return (
        <>
            <section className="anime-gallery container mx-auto grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 px-3 py-3 mt-20">
                {animeList.map((anime, index) => (
                    <article className="anime-card flex mx-3 my-2 rounded-lg h-72 bg-gray-dark shadow-md hover:-translate-y-3" key={anime.mal_id}>
                        <img className="anime-card-poster h-72" src={anime.images.jpg.image_url} alt={anime.title} />
                        <div className="anime-details p-3 w-full flex flex-col overflow-ellipsis overflow-auto">
                            <h3 className="anime-card-title text-xl tracking-wide text-balance text-baby-blue font-bold"> {anime.title}</h3>
                            <p className="anime-card-synopsis text-sm mt-2 text-gray-light"> Episodes: {anime.episodes || 'N/A'}</p>
                            <p className="anime-card-rating text-sm text-gray-light"> Rating: {anime.score}</p>
                            <p className="anime-card-status text-sm text-gray-light"> Status: {anime.status}</p>
                            <p className="anime-genres text-sm text-gray-light flex flex-wrap">
                                {anime.genres.map((genre) => (
                                    <p key={genre.mal_id} className="genre-btn px-2 bg-seafoam ms-1 rounded-lg mb-1 mt-2">{genre.name}</p>
                                ))}
                            </p>
                        </div>
                    </article>
                ))}
            </section>
        </>
    )
}

export default AnimeGallery;

仓库链接

对于重复的标题,我确实尝试设置一个键以等于 API 中节目的特定 id,但重复项仍然存在,并且我还尝试使用缩减方法来代替我的过滤器。

我还尝试利用派生状态并将我的状态变量animeList保留为动画的唯一完整列表,然后另一种状态仅用于我的搜索查询,以便我可以在渲染中设置过滤器和规范,我没有注意到任何变化也可以使用这种方法,但公平地说,我必须对派生状态的概念进行大量研究,所以也许我没有很好地实现它。

javascript reactjs api duplicates rendering
1个回答
0
投票

API 响应中存在重复的

mal_id
,因此使用它作为键渲染列表会在更新列表时出现问题。

尝试创建您自己的 ID,如下所示。

useEffect(() => {
    const fetchAnimeGenre = async () => {
      const result = await fetch(animeApi);
      const data = await result.json();
      const transformedData = data.data.map((obj) => ({
        ...obj,
        id: crypto.randomUUID()
      }));
      setAnimeList(transformedData);
      setFilteredAnime(transformedData);
    };
    fetchAnimeGenre();
  }, []);

确保您也使用这个新 ID 作为列表中的键。

key={anime.id}

© www.soinside.com 2019 - 2024. All rights reserved.