I’m using the Jikan API to create an anime gallery of some sort, one of the features I wanted to include was to be able to search for a specific anime title within the gallery. My issue is that with my current search input field; despite specifying a show, it will show the specific title you searched for along with a couple of duplicated titles of an entirely different show.
Another issue I’m having is that despite setting a limit to how many shows data will be fetched, once I clear the search field, those same duplicates will be added onto the gallery despite the limitation.
App.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;
For the duplicated titles I did try setting a key to equal the specific id of the show from the API but the duplicates are still present, and I’d also tried using a reduce method in place of my filter.
I also tried utilizing derived state and kept my state variable animeList
as the only and entire list of the anime then one other state just for my search query so I could set the filter and specifications within my render, I didn’t notice any changes with that approach either, but to be fair, I had to do a lot of research on the concept of derived state so perhaps I didn’t implement it well.
2
Answers
There is a duplicate
mal_id
in the API response, hence rendering a list with that as a key causes problems while updating the list.Try creating your own ids like below.
Make sure you also use this new id as the key in the list.
key={anime.id}
Certainly! If you’d like to change the
key
in yourmap
function to use theindex
instead ofanime.mal_id
, you can simply replaceanime.mal_id
withindex
in thekey
prop.Here’s the modified version of your component:
Explanation:
key
in themap
method has been changed toindex
. Thekey
should be a unique value to help React efficiently update and render components, but usingindex
is okay when the list doesn’t change dynamically (e.g., items being added, removed, or reordered). However, if the list changes often, using a unique identifier likeanime.mal_id
is typically recommended to avoid potential rendering issues.Let me know if you need any further clarification!
enter link description here