I have a React component that try to load movies first from tmdb API. Then, I create a button to sort the movies using query params. I want to use query params because I want to preserve the URL so that I can share the URL with sort value. (This is for my learning purpose also).
When the page is already rendered and I click the button, it's work fine.
But when I try to reload the page with query params, the query params useEffect is run first before the movies finished loaded.
Here is my code:
import { Box, Button } from '@mui/material';
import { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import tmdb from '../apis/tmdb';
import MovieCard from '../components/MovieCard';
const MovieList = () => {
const [queryParams, setQueryParams] = useSearchParams();
const [movies, setMovies] = useState([]);
useEffect(() => {
const fetchMovies = async () => {
try {
const fetchedMovies = await tmdb.get("trending/movie/week");
setMovies(fetchedMovies.data.results);
} catch (error) {
console.log(error);
}
}
fetchMovies();
}, []);
useEffect(() => {
const sortMovies = (type) => {
if (type === 'asc') {
const sorted = movies.sort((a, b) => a.vote_average - b.vote_average);
setMovies(sorted);
}
if (type === 'desc') {
const sorted = movies.sort((a, b) => b.vote_average - a.vote_average);
setMovies(sorted);
}
}
sortMovies(queryParams.get('sort'));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [queryParams]);
const setSortParam = (type) => {
queryParams.set("sort", type);
setQueryParams(queryParams);
}
return (
<Box sx={{
display: 'flex',
flexDirection: 'column',
mt: 5,
}}>
<Box sx={{
mt: 5,
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
}}>
Sort by Rating
<Button
variant="contained"
sx={{ ml: 2 }}
onClick={() => setSortParam("asc")}
>
Asc
</Button>
<Button
variant="contained"
sx={{ ml: 2, mr: 2 }}
onClick={() => setSortParam("desc")}
>
Desc
</Button>
</Box>
<Box sx={{
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
}}>
{
movies.map(movie => (
<MovieCard key={movie.title} movie={movie}></MovieCard>
))
}
</Box>
</Box>
);
}
export default MovieList;
I try to create new state to track if the movies length > 0, but sometimes it's buggy. I also try to useRef to track if the movies length > 0 but it's not working.
Is there anyway to wait for first useEffect to finish? Or should I use other approach than useEffect to read query params and sort?