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