I am using react useParams to show a singleMovie (details). I have also a condition that if there is no picture (in the API) to show a stock picture. However, the problem is that when I access the single movie detail the stock photo shows first then the API picture.
How can I fix this or add a spinner so that I dont see the stock photo first.
import React from 'react'
import { Link, useParams } from 'react-router-dom';
import { useState, useEffect } from 'react';
import { API_KEY, IMAGE_BASE_URL } from '../config';
import NoCover from '../img/no-cover.jpg'
const SingleMovie = () => {
const { movieId } = useParams();
const MOVIE_API = `https://api.themoviedb.org/3/movie/${movieId}?api_key=${API_KEY}&language=en-US`;
//useState
const [movieDetails, setMovieDetails] = useState([])
//functions
const getMovieDetails = async (API) => {
const response = await fetch(API)
const data = await response.json()
//console.log(data);
setMovieDetails(data)
}
//useEffect
useEffect(() => {
getMovieDetails(MOVIE_API)
}, [MOVIE_API])
const { title, poster_path } = movieDetails
return (
<>
<h1>{title}</h1>
<div>
{poster_path ? (<img src={`${IMAGE_BASE_URL}${poster_path}`} alt={title} />) : (<img src={NoCover} alt={title} />)}
</div>
<Link to="/">Go Back</Link>
</>
);
}
export default SingleMovie
CodePudding user response:
Hey what you can do is create a boolean useState
to display a Loading... while getting the data. Like this:
Add:
const [loading, setLoading] = useState(false);
The function that gets the data, there I added a try catch
so also you see if there is an error.
const getMovieDetails = async (API) => {
setLoading(true);
try {
const response = await fetch(API);
const data = await response.json();
//console.log(data);
setMovieDetails(data);
} catch (error) {
console.log('Error', error);
} finally {
setLoading(false);
}
};
And then you can add this ternary in the return:
{!loading ? (
<div>
{poster_path ? (
<img src={`${IMAGE_BASE_URL}${poster_path}`} alt={title} />
) : (
<img src={NoCover} alt={title} />
)}
</div>
) : (
'Loading...'
)}
Where I added the text Loading...
, you can add a spinner component or whatever you want!
CodePudding user response:
define a state variable loading
can be solved
Try out this code
import React from 'react'
import { Link, useParams } from 'react-router-dom';
import { useState, useEffect } from 'react';
import { API_KEY, IMAGE_BASE_URL } from '../config';
import NoCover from '../img/no-cover.jpg'
const SingleMovie = () => {
const { movieId } = useParams();
const MOVIE_API = `https://api.themoviedb.org/3/movie/${movieId}?api_key=${API_KEY}&language=en-US`;
//useState
const [movieDetails, setMovieDetails] = useState([])
const [loading, setLoading] = React.useState(true); //
//functions
const getMovieDetails = async (API) => {
const response = await fetch(API)
if(response.ok){ //
const data = await response.json()
//console.log(data);
setMovieDetails(data);
setLoading(false); //
} //
}
//useEffect
useEffect(() => {
getMovieDetails(MOVIE_API)
}, [MOVIE_API])
const { title, poster_path } = movieDetails
return (
<>
<h1>{title}</h1>
//
{loading ? "spinner" : (<>
<div>
{poster_path ? (<img src={`${IMAGE_BASE_URL}${poster_path}`} alt={title} />) : (<img src={NoCover} alt={title} />)}
</div>
</>)}
//
<Link to="/">Go Back</Link>
</>
);
}
export default SingleMovie