aleks3650 Posted April 16 Share Posted April 16 hello, I have some issue with me react app. Im trying to create animation to my page and everything is working properly untill user choose wrong country, than app crash with error code: Rendered fewer hooks than expected. This may be caused by an accidental early return statement. Animation itself works properly. And additionaly i see warning: GSAP target undefined not found. I would be greatful for answear import { useEffect, useRef, useState } from "react"; import { gsap } from "gsap"; import { useGSAP } from "@gsap/react"; import { TextPlugin } from "gsap/TextPlugin"; function App() { gsap.registerPlugin(useGSAP, TextPlugin); const UsaFlag = "url('https://flagcdn.com/w320/us.png')"; const [FirstCountry, setFirstCountry] = useState(""); const [FirstCountryInfo, setFirstCountryInfo] = useState(null); const [SecondCountry, setSecondCountry] = useState(""); const [SecondCountryInfo, setSecondCountryInfo] = useState(null); const [AnotherCountry, setAnotherCountry] = useState(""); const [AnotherCountryInfo, setAnotherCountryInfo] = useState(null); const [error, setError] = useState(null); const [choosed, setChoosed] = useState(false); const [gameOver, setGameOver] = useState(false); const [newSize, setNewSize] = useState(""); const lowerref = useRef(); const upperref = useRef(); async function fetchData() { try { const response = await fetch("https://restcountries.com/v3.1/all"); const data = await response.json(); const randomIndex = Math.floor(Math.random() * data.length); const randomCountry = data[randomIndex]; const name = randomCountry.name.common; setFirstCountry(name); const secondRandomIndex = Math.floor(Math.random() * data.length); const secondRandomCountry = data[secondRandomIndex]; const secondName = secondRandomCountry.name.common; setSecondCountry(secondName); } catch (error) { setError("Failed to fetch data. Please try again later."); } } async function fetchSingleData(chosenCountry, index) { try { const response = await fetch( `https://restcountries.com/v3.1/name/${chosenCountry}` ); const data = await response.json(); if (data && data.length > 0) { if (index === 1) setFirstCountryInfo(data[0]); if (index === 2) { setSecondCountryInfo(data[0]); setNewSize(`${NameFun(data[0].area.toString())} km²`); } } else { setError(`No data found for ${chosenCountry}.`); } } catch (error) { setError(`Failed to fetch data for ${chosenCountry}.`); } } async function fetchAnotherDataInfo() { const response = await fetch("https://restcountries.com/v3.1/all"); const data = await response.json(); const randomIndex = Math.floor(Math.random() * data.length); const randomCountry = data[randomIndex]; const name = randomCountry.name.common; setAnotherCountry(name); try { const response = await fetch( `https://restcountries.com/v3.1/name/${name}` ); const data = await response.json(); if (data && data.length > 0) { setAnotherCountryInfo(data[0]); } else { setError(`No data found for ${name}.`); } } catch (error) { setError(`Failed to fetch data for ${name}.`); } } useEffect(() => { fetchData(); }, []); useEffect(() => { if (FirstCountry) { fetchSingleData(FirstCountry, 1); } if (SecondCountry) { fetchSingleData(SecondCountry, 2); } }, [FirstCountry, SecondCountry]); useEffect(() => { fetchAnotherDataInfo(); }, [FirstCountry, SecondCountry]); if (error) { return <div className="errorr">Error: {error}</div>; } const handleNextOne = () => { setFirstCountry(SecondCountry); setSecondCountryInfo(SecondCountryInfo); // setNewSize(SecondCountryInfo.area.toString()); setSecondCountry(AnotherCountry); setAnotherCountryInfo(AnotherCountryInfo); setChoosed(false); }; const handleTryAgain = () => { setGameOver(false); setChoosed(false); setError(false); setFirstCountry(false); setFirstCountryInfo(false); setSecondCountry(false); setSecondCountryInfo(false); fetchData(); }; const handleGameOver = () => { setGameOver(true); }; const handleCompare = (value) => { setChoosed(true); fetchAnotherDataInfo(); setTimeout(() => { if ( (FirstCountryInfo.area <= SecondCountryInfo.area && value === "more") || (FirstCountryInfo.area >= SecondCountryInfo.area && value === "less") ) { handleNextOne(); } else { handleGameOver(); } }, "1000"); }; const NameFun = (area) => { let numStr = area.toString(); if (numStr.includes(".")) { return area; } let newtab = []; for (let i = numStr.length; i > 0; i -= 3) { let chunk = numStr.slice(Math.max(0, i - 3), i); newtab.unshift(chunk); } let spacedNum = newtab.join(" "); return spacedNum; }; const styleh1 = { letterSpacing: "10px", }; if (gameOver) { return ( <div className="GameOverScreen"> <h1 style={styleh1}>GAME OVER</h1> <p>You can do better</p> <button className="more tryAgain" onClick={() => handleTryAgain()}> TRY AGAIN </button> </div> ); } useGSAP( () => { gsap.to(lowerref.current, { duration: 0.9, delay: 0.1, text: newSize, ease: "bounce.inOut", }); }, { dependencies: [AnotherCountryInfo] } ); return ( <> <div className="app"> <h1>More or less</h1> <div className="container"> <div className="versus">VS</div> <div className="country first" style={{ backgroundImage: FirstCountryInfo ? `linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(${ FirstCountryInfo.flags ? FirstCountryInfo.flags.png : "" })` : "", }}> <h2> {FirstCountryInfo ? FirstCountryInfo.name.common || "Country" : "Loading..."} </h2> <p>is</p> <h3> <span> {FirstCountryInfo ? `${NameFun(FirstCountryInfo.area) || "Area"} km²` : "Loading..."} </span> </h3> <p>in total area</p> </div> <div className="country second" ref={upperref} style={{ backgroundImage: SecondCountryInfo ? `linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(${ SecondCountryInfo.flags ? SecondCountryInfo.flags.png : "" })` : "", }}> <h2> {SecondCountryInfo ? `${SecondCountryInfo.name.common || "Country"}` : "Loading..."} </h2> <p>is</p> {choosed ? ( <h3> <span className="AreaInfo" ref={lowerref}> XXXXXXXXXXX km² </span> </h3> ) : ( // {NameFun(newSize) || "Area"} <div className="buttonContainer"> <button className="less" onClick={() => handleCompare("less")}> smaller </button> <button className="more" onClick={() => handleCompare("more")}> bigger </button> </div> )} <p>in Total Area</p> </div> <div className="country third" style={{ backgroundImage: UsaFlag }}></div> </div> </div> </> ); } export default App; App.jsx Link to comment Share on other sites More sharing options...
Rodrigo Posted April 16 Share Posted April 16 Hi @aleks3650 and welcome to the GSAP Forums! There is far too much code in here and without a minimal demo there is not a lot we can do. The first error you're getting is mostly a React related one and not a GSAP related one: https://dev.to/collegewap/fix-rendered-fewer-hooks-than-expected-in-react-3757 https://medium.com/@jonchurch/how-to-fix-react-error-rendered-fewer-hooks-than-expected-e6a378985d3c The issue with the target undefined, that means that the element you're passing to GSAP is undefined most likely because of that conditional rendering block you have here: {choosed ? ( <h3> <span className="AreaInfo" ref={lowerref}> XXXXXXXXXXX km² </span> </h3> ) : ( // {NameFun(newSize) || "Area"} <div className="buttonContainer"> <button className="less" onClick={() => handleCompare("less")}> smaller </button> <button className="more" onClick={() => handleCompare("more")}> bigger </button> </div> )} When choosed is falsy lowerref is no longer a DOM element but is undefined: useGSAP( () => { gsap.to(lowerref.current, { // UNDEFINED -> WARNING! duration: 0.9, delay: 0.1, text: newSize, ease: "bounce.inOut", }); }, { dependencies: [AnotherCountryInfo] } ); I would suggest you to use revertOnUpdate in the useGSAP hook, but I'm afraid that it won't fix the logic issue of the ref not being defined. You should look into that first. We have a collection of starter templates in Stackblitz where you can fork one of those and create a minimal demo: https://stackblitz.com/@gsap-dev/collections/gsap-react-starters Happy Tweening! Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now