I am building a guessing game built wtih react and "artsy.api". The guessing game can be accessed through my index page by clicking a button.
<Link to="/guessing-game">
{" "}
{/* Link to Guessing Game page */}
<Button type="primary">Play Guessing Game</Button>{" "}
{/* Button to navigate to Guessing Game page */}
</Link>
Whenever I press the button to navigate to the guessing game page, the page becomes un responsive and only displayes "Guess the Artist" and directly underneath "Loading…". I cant even right click and inspect the page to check for the errors in the console.
GuessingsGame.tsx:
import React, { useState, useEffect } from "react";
import axios from "axios"; // Import Axios
import "./GuessingGame.css";
interface Artwork {
_embedded: {
artists: { name: string }[];
};
_links: {
thumbnail: { href: string };
artists: { href: string };
};
title: string;
}
const GuessingGame: React.FC = () => {
const [artwork, setArtwork] = useState<Artwork | null>(null);
const [options, setOptions] = useState<string[]>([]);
const [selectedOption, setSelectedOption] = useState<string | null>(null);
const [score, setScore] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
const fetchArtworkData = async () => {
try {
const response = await axios.get("https://api.artsy.net/api/artworks", {
headers: {
"X-XAPP-Token":
"My_API_KEY",
},
});
const { _embedded } = response.data;
if (_embedded && _embedded.artworks && _embedded.artworks.length > 0) {
const randomArtwork: Artwork =
_embedded.artworks[
Math.floor(Math.random() * _embedded.artworks.length)
];
setArtwork(randomArtwork);
const randomArtists = await getRandomArtists(
randomArtwork._links.artists.href
);
const correctArtist = randomArtwork._embedded.artists[0].name;
setOptions([...randomArtists, correctArtist]);
setLoading(false);
}
} catch (error) {
console.error("Error fetching artwork data:", error);
setLoading(false);
}
};
fetchArtworkData();
}, []);
const getRandomArtists = async (artistsLink: string): Promise<string[]> => {
try {
const response = await axios.get(artistsLink, {
headers: {
"X-XAPP-Token":
"My_API_KEY",
},
});
const { _embedded } = response.data;
if (_embedded && _embedded.artists) {
const randomArtists: string[] = [];
while (randomArtists.length < 3) {
const randomIndex = Math.floor(
Math.random() * _embedded.artists.length
);
const randomArtist = _embedded.artists[randomIndex].name;
if (!randomArtists.includes(randomArtist)) {
randomArtists.push(randomArtist);
}
}
return randomArtists;
}
} catch (error) {
console.error("Error fetching artists:", error);
}
return [];
};
const handleOptionSelect = (option: string) => {
setSelectedOption(option);
if (option === artwork?._embedded.artists[0].name) {
setScore(score + 1);
}
};
return (
<div className="guessing-game-container">
<h1>Guess the Artist</h1>
{loading ? (
<p>Loading...</p>
) : artwork ? (
<div>
<img
src={artwork._links.thumbnail.href}
alt={artwork.title}
className="artwork-thumbnail"
/>
<h2>{artwork.title}</h2>
<h3>Options:</h3>
<div className="options-container">
{options.map((option, index) => (
<button
key={index}
onClick={() => handleOptionSelect(option)}
className={`option-button ${
selectedOption === option ? "selected" : ""
}`}
>
{option}
</button>
))}
</div>
<p>Score: {score}</p>
</div>
) : (
<p>No artwork available</p>
)}
</div>
);
};
export default GuessingGame;
Can someone suggest a solution to ammends the code or a different approach to solving the problem?
Ive attempted to add a debounce function to limit the number of API calls, as this is the only aspect that i think could be casuing the problem but it hasnt seemed to solve the problem.
import React, { useState, useEffect } from "react";
import "./GuessingGame.css";
interface Artwork {
_embedded: {
artists: { name: string }[];
};
_links: {
thumbnail: { href: string };
artists: { href: string };
};
title: string;
}
const GuessingGame: React.FC = () => {
const [artwork, setArtwork] = useState<Artwork | null>(null);
const [options, setOptions] = useState<string[]>([]);
const [selectedOption, setSelectedOption] = useState<string | null>(null);
const [score, setScore] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
const fetchArtworkData = async () => {
try {
const response = await fetch("https://api.artsy.net/api/artworks", {
headers: {
"X-XAPP-Token":
"eyJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6IiIsInN1YmplY3RfYXBwbGljYXRpb24iOiIzMDU2MDk0Yi05ODUwLTRjYTktOTJiNy05MWM4MWYwZTYyNDYiLCJleHAiOjE3MTUzMzQ0MDUsImlhdCI6MTcxNDcyOTYwNSwiYXVkIjoiMzA1NjA5NGItOTg1MC00Y2E5LTkyYjctOTFjODFmMGU2MjQ2IiwiaXNzIjoiR3Jhdml0eSIsImp0aSI6IjY2MzRiMjg1MTc0YmUxMDAxMmRiNDc2ZSJ9.hGIPQb-W4jHjitTo5KGWguRo0YpRqlUNIAQlKJpaDl8",
},
});
const { _embedded } = await response.json();
if (_embedded && _embedded.artworks && _embedded.artworks.length > 0) {
const randomArtwork: Artwork =
_embedded.artworks[
Math.floor(Math.random() * _embedded.artworks.length)
];
setArtwork(randomArtwork);
const randomArtists = await getRandomArtists(
randomArtwork._links.artists.href
);
const correctArtist = randomArtwork._embedded.artists[0].name;
setOptions([...randomArtists, correctArtist]);
setLoading(false);
}
} catch (error) {
console.error("Error fetching artwork data:", error);
setLoading(false);
}
};
fetchArtworkData();
}, []);
const getRandomArtists = async (artistsLink: string): Promise<string[]> => {
try {
const response = await fetch(artistsLink, {
headers: {
"X-XAPP-Token":
"eyJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6IiIsInN1YmplY3RfYXBwbGljYXRpb24iOiIzMDU2MDk0Yi05ODUwLTRjYTktOTJiNy05MWM4MWYwZTYyNDYiLCJleHAiOjE3MTUzMzQ0MDUsImlhdCI6MTcxNDcyOTYwNSwiYXVkIjoiMzA1NjA5NGItOTg1MC00Y2E5LTkyYjctOTFjODFmMGU2MjQ2IiwiaXNzIjoiR3Jhdml0eSIsImp0aSI6IjY2MzRiMjg1MTc0YmUxMDAxMmRiNDc2ZSJ9.hGIPQb-W4jHjitTo5KGWguRo0YpRqlUNIAQlKJpaDl8",
},
});
const { _embedded } = await response.json();
if (_embedded && _embedded.artists) {
const randomArtists: string[] = [];
while (randomArtists.length < 3) {
const randomIndex = Math.floor(
Math.random() * _embedded.artists.length
);
const randomArtist = _embedded.artists[randomIndex].name;
if (!randomArtists.includes(randomArtist)) {
randomArtists.push(randomArtist);
}
}
return randomArtists; // Add return statement here
}
} catch (error) {
console.error("Error fetching artists:", error);
}
return []; // Add return statement here to handle other cases
};
const handleOptionSelect = (option: string) => {
setSelectedOption(option);
if (option === artwork?._embedded.artists[0].name) {
setScore(score + 1);
}
};
return (
<div className="guessing-game-container">
<h1>Guess the Artist</h1>
{loading ? (
<p>Loading...</p>
) : artwork ? (
<div>
<img
src={artwork._links.thumbnail.href}
alt={artwork.title}
className="artwork-thumbnail"
/>
<h2>{artwork.title}</h2>
<h3>Options:</h3>
<div className="options-container">
{options.map((option, index) => (
<button
key={index}
onClick={() => handleOptionSelect(option)}
className={`option-button ${
selectedOption === option ? "selected" : ""
}`}
>
{option}
</button>
))}
</div>
<p>Score: {score}</p>
</div>
) : (
<p>No artwork available</p>
)}
</div>
);
};
export default GuessingGame;
2
Answers
I fetch the artist directly in the getRandomArtists function instead of using the artistLink.
Solution:
You have an infinite loop in your code in the
getRandomArtists()
function:the condition in the while loop never became false because
_embedded.artists.length
most of the time is 1 sorandomArtists
will always contains one element because you check!randomArtists.includes(randomArtist)
and this will be always falseI hope you understand the logic 🙂
Solution:
you can get artists directly from the API: