I am creating a movie website using TMDB API and having a problem with searching with infinite scroll.
The search function is working fine. Movies change when I search another movie.
However, when I scroll down 3~4 pages and make another search, I see new movies with old movies.
I consoled “page” on the loader, page changed like this: 1,2,3,4 -> 1,4
<Form method="get" action="/search">
<input type="text" name="query" />
<button type="submit">Search</button>
</Form>
Here is in Navigation.tsx
export async function loader({ request }: ActionFunctionArgs) {
const url = new URL(request.url);
const searchQuery = url.searchParams.get("query");
console.log(url);
const page = url.searchParams.get("page") || "1";
const apiUrl = `https://api.themoviedb.org/3/search/movie?query=${searchQuery}&include_adult=false&language=en-US&page=${page}`;
const res = await fetch(apiUrl, {
method: "GET",
headers: {
accept: "application/json",
Authorization: `${process.env.SOME_SECRET}`,
},
});
if (!res.ok) {
throw new Response("Failed to fetch data", { status: res.status });
}
const nowPlayingMovies = await res.json();
return json({ nowPlayingMovies, searchQuery });
}
const InfiniteScroller = (props: {
children: any;
loading: boolean;
loadNext: () => void;
}) => {
const { children, loading, loadNext } = props;
const scrollListener = useRef(loadNext);
useEffect(() => {
scrollListener.current = loadNext;
}, [loadNext]);
const onScroll = () => {
const documentHeight = document.documentElement.scrollHeight;
const scrollDifference = Math.floor(window.innerHeight + window.scrollY);
const scrollEnded = documentHeight === scrollDifference;
if (scrollEnded && !loading) {
scrollListener.current();
}
};
useEffect(() => {
if (typeof window !== "undefined") {
window.addEventListener("scroll", onScroll);
}
return () => {
window.removeEventListener("scroll", onScroll);
};
}, []);
return <>{children}</>;
};
export default function Search() {
const { nowPlayingMovies, searchQuery } = useLoaderData<typeof loader>();
const fetcher = useFetcher<FetcherMovies>();
const navigation = useNavigation();
const [items, setItems] = useState(nowPlayingMovies);
const [currentQuery, setCurrentQuery] = useState(searchQuery);
const searching =
navigation.location &&
new URLSearchParams(navigation.location.search).has("query");
useEffect(() => {
if (searchQuery !== currentQuery) {
setItems(nowPlayingMovies);
setCurrentQuery(searchQuery);
}
}, [searchQuery, nowPlayingMovies, currentQuery]);
useEffect(() => {
if (!fetcher.data || fetcher.state === "loading") {
return;
}
if (fetcher.data) {
const newItems = fetcher.data.nowPlayingMovies.results;
setItems((prevItems) => ({
...prevItems,
results: [...prevItems.results, ...newItems],
}));
}
}, [fetcher.data]);
return (
<PageMargin>
<Typography variant="h6" style={{ textAlign: "center" }}>
Result from your search : {searchQuery}
</Typography>
<InfiniteScroller
loadNext={() => {
const nextPage =
fetcher.data && fetcher.data.nowPlayingMovies
? fetcher.data.nowPlayingMovies.page + 1
: nowPlayingMovies.page + 1;
console.log(nextPage);
fetcher.load(`?query=${searchQuery}&page=${nextPage}`);
}}
loading={fetcher.state === "loading"}
>
{searching ? (
"loading..."
) : (
<div
style={{
display: "flex",
flexFlow: "wrap",
justifyContent: "space-evenly",
}}
>
{items?.results.map((movie: MovieResult) => (
<Card key={movie.id} sx={{ width: 300, margin: "40px 20px" }}>
<Link to={`/movie/detail/${movie.id}`}>
<CardMedia
component="img"
height="250"
src={"https://image.tmdb.org/t/p/w500/" + movie.poster_path}
alt={movie.original_title}
/>
</Link>
<CardContent>
<Typography gutterBottom variant="h5" component="div">
{movie.original_title}
</Typography>
<Typography
sx={{
overflow: "hidden",
textOverflow: "ellipsis",
display: "-webkit-box",
WebkitLineClamp: "3",
WebkitBoxOrient: "vertical",
}}
variant="body2"
color="text.secondary"
>
{movie.overview
? movie.overview
: "No overview for this movie."}
</Typography>
</CardContent>
</Card>
))}
</div>
)}
</InfiniteScroller>
</PageMargin>
);
}