I have an issue where my app crashes upon searching. I suspect this is because at some point during rendering the artist container is trying to render the code but there is no image url even so when I put a backup URL e.g. src={props.artist.images[0].url || "backup url"} it still fails. If y try to just load artist name I have no issues but the image is the Achilles heel here. I have spent a lot of time trying to figure out why it is crashing but to no avail.
Also artist container should only be rendering if we do have artist results ... so a bit confused as to why it is saying URL not defined. 99% of these results have images.
const [query, setQuery] = useState("")
const [artistResults, setArtistResults] = useState(null)
const fetchQueryArtists = async () => {
try {
let response = await fetch(`${ApiUrl}/search?q=${query}&type=artist`, {
headers: {
"Authorization": "Bearer " + props.token
}
})
if (response.ok) {
let json = await response.json()
console.log(json.artists.items)
setArtistResults(json.artists.items)
}
} catch (error) {
console.log(error)
}
}
useEffect(() => {
if (query.length > 1) {
fetchQueryArtists()
fetchQueryTracks()
fetchQueryAlbums()
}
}, [query])
Inside my return is this:
{query.length > 0 && artistResults &&
<h3 className="py-3 px-2">Artists</h3>}
{artistResults && artistResults.length > 0 ? artistResults.slice(0, 6).map(artist => {
return <ArtistContainer key={artist.id} artist={artist} />
}) : <h1>Test flag</h1>}
This is my artist container:
return (
<div onClick={directToPlaylist} className="category-container d-flex align-items-center justify-content-center mb-4 col-6 col-md-4 col-lg-3 col-xl-2">
<img className="img-fluid" height={150} src={props.artist.images[0].url} alt="playlist-cover" />
<div>
<span>{props.artist.name}</span>
<p className="text-muted">Artist</p>
</div>
</div>
);
This is the JSON (just in case you think I am accessing the images incorrectly):
Array(20)
0:
external_urls: {spotify: "https://open.spotify.com/artist/3TVXtAsR1Inumwj472S9r4"}
followers: {href: null, total: 55327781}
genres: (6) ["canadian hip hop", "canadian pop", "hip hop", "pop rap", "rap", "toronto rap"]
href: "https://api.spotify.com/v1/artists/3TVXtAsR1Inumwj472S9r4"
id: "3TVXtAsR1Inumwj472S9r4"
images: Array(3)
0: {height: 640, url: "https://i.scdn.co/image/60cfab40c6bb160a1906be45276829d430058005", width: 640}
1: {height: 320, url: "https://i.scdn.co/image/5ea794cf832550943d5f8122afcf5f23ee9d85b7", width: 320}
2: {height: 160, url: "https://i.scdn.co/image/8eaace74aaca82eaccde400bbcab2653b9cf86e1", width: 160}
length: 3
__proto__: Array(0)
name: "Drake"
popularity: 98
type: "artist"
uri: "spotify:artist:3TVXtAsR1Inumwj472S9r4"
__proto__: Object
Use this:
src={props.artist.images[0]?.url || "backup url"}
I've use something called as optional chaining here. You can read more about it here
Detailed Explanation:
Before the api call, the react renders the component, that time:
props.artist.images = [].
So before we fetch the data, it would be an empty array, accessing first element of that gives undefined.
Therefore, you try to access undefined.url, this gives an error.
Now more about optional chaining:
The optional chaining operator (?.) enables you to read the value of a property located deep within a chain of connected objects without having to check that each reference in the chain is valid.
Traditionally if we have to safely access nested elements, we do:
const obj = {
name: {
first: "foo",
last: "bar"
}
};
// Getting first element
const firstName = obj && obj.name && obj.name.first ? obj.name.first : "fallback";
// optional chaining
const firstElement = obj?.name?.first || "fallback"
Summarising example:
// This raises TypeError
console.log(undefined.someKey)
// Optinal chaining gives safety net and does not give TypeError
console.log(undefined?.somKey);
About Browser Support and Usage: This may not work with older browser due to compatibility issue. Check here
Also note, if you're using Typescript > 3.7 then optional chaining can work for older browsers as well (since Babel accordingly transpiles to target the configured browsers).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With