State causing iframe to reload
Answered
Scottish Fold posted this in #help-forum
Scottish FoldOP
I have the following react component:
When I click the Star icon, the component re renders and the iframe, which I don't want. I'm assuming it has something to do with the fetch() request, so is there anything I can do to prevent this?
'use client'
import { Skeleton } from '@/components/ui/skeleton'
import ErrorMessage from '@/components/ErrorMessage'
import { Star, Maximize } from 'lucide-react'
import { Game } from '@/app/api/games/all/route'
import { encodeXor, fetcher } from '@/lib/utils'
import { useState, useEffect, useRef } from 'react'
import { toast } from 'sonner'
import { notFound } from 'next/navigation'
import useSWR from 'swr/immutable'
export default function GameFrame({ params }: { params: { game: string } }) {
const [favorited, setFavorited] = useState<boolean>(false)
useEffect(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/uv/sw.js', {
scope: '/uv/service'
})
.then(() => {
if (frameRef.current && game) {
// @ts-ignore
frameRef.current.src = '/uv/service/' + encodeXor(game.url)
}
})
} else {
toast.error('Service workers are not supported on this device. Art Class will not function correctly.')
}
})
const { data: game, error, isLoading } = useSWR<Game>(`/api/games/all?game=${params.game}`, fetcher)
const frameRef = useRef<HTMLIFrameElement>(null)
useEffect(() => {
if (game) {
;(async () => {
const res = await fetch('/api/games/favorites')
const favorites = (await res.json()) as Game[]
if (favorites.some((item) => item.id == game.id)) {
setFavorited(true)
}
})()
}
}, [game])
if (error) return <ErrorMessage />
if (isLoading) {
return (
<div className="flex flex-col h-[90vh] p-12 px-20 rounded-md border-border border">
<Skeleton className="h-full rounded-md" />
</div>
)
}
if (!game || !game.id) return notFound()
return (
<div className="flex flex-col h-[90vh] p-12 px-20 rounded-md border-border border">
<iframe ref={frameRef} className="bg-white h-full rounded-t-md"></iframe>
<div className="p-4 bg-gray-800 flex justify-between rounded-b-md">
<span>
<span className="flex gap-3 mb-2 items-center">
<img src={game.image} className="h-8 w-8 rounded-md" />
<h1 className="text-xl font-bold">{game.title}</h1>
</span>
<p className="text-md text-gray-400 font-medium">{game.author}</p>
<p className="text-md text-gray-400 font-medium mt-2">{game.description}</p>
</span>
<div className="flex gap-4 my-auto mx-4 items-center [&>*]:cursor-pointer">
<Star
onClick={async () => {
const res = await fetch(`/api/games/favorites?id=${game.id}`, {
method: 'POST'
})
const favorites = (await res.json()) as string[]
setFavorited(favorites.includes(game.id))
}}
fill={favorited ? '#FFD900' : '#FFFFFF'}
className={favorited ? 'text-[#FFD900]' : ''}
/>
<Maximize
strokeWidth={2}
onClick={() => {
if (!(frameRef.current && frameRef.current.contentWindow)) return
frameRef.current.requestFullscreen()
}}
/>
</div>
</div>
</div>
)
}When I click the Star icon, the component re renders and the iframe, which I don't want. I'm assuming it has something to do with the fetch() request, so is there anything I can do to prevent this?
52 Replies
Barbary Lion
Try to do it in its own function instead of doing it inside the onClick like this:
async function getGame() {
const res = await fetch("path", {method: "POST"});
const data = await res.json();
}
return (
#Unknown Channel
<main>
<button onClick={() => getGame()}>test</button>
</main>
</>
);
async function getGame() {
const res = await fetch("path", {method: "POST"});
const data = await res.json();
}
return (
#Unknown Channel
<main>
<button onClick={() => getGame()}>test</button>
</main>
</>
);
Scottish FoldOP
Alright
Scottish FoldOP
That didn't work
commenting this out fixes the problem, which leads me to believe that its a state issue
yeah it only occurs when setting the state
I don't know enough about react state to know how to prevent this :/
@Scottish Fold commenting this out fixes the problem, which leads me to believe that its a state issue
try moving the function outside of the component
Scottish FoldOP
setFavorited wouldn’t be in the scope then
@Scottish Fold setFavorited wouldn’t be in the scope then
oh didn't notice
hm
can you make a [minimal reproduction repository](https://nextjs-faq.com/minimal-reproduction-repository)?
Scottish FoldOP
sure
Scottish FoldOP
very odd, I made a reproduction repository and the problem isn't appearing on there
but it still is doing it on the main repository
@Scottish Fold but it still is doing it on the main repository
start adding stuff back until the problem reappears
maybe you were on an outdated version of nextjs; i've seen problems fixed by updating
Scottish FoldOP
alright
actually that could be a thing
nope that wasn't it
Scottish FoldOP
https://github.com/proudparrot2/nextjs-issue (issue fixed)
https://github.com/art-class/v5 (is where the issue is)
go to /games, click on 8 ball pool, and try to click the star
on the first one you won't see anything happen besides the star change color, which is the whole goal of what I'm doing with state) but the second one reloads the iframe when you click the star
https://github.com/art-class/v5 (is where the issue is)
go to /games, click on 8 ball pool, and try to click the star
on the first one you won't see anything happen besides the star change color, which is the whole goal of what I'm doing with state) but the second one reloads the iframe when you click the star
Scottish FoldOP
oh shoot wait
thats an old commit
ok pull
make sure to run start.ts so the game frame doesn't crash
Scottish FoldOP
are you seeing anything
@Scottish Fold are you seeing anything
it is rerendering the component
Scottish FoldOP
what about on the other one
the first one
Scottish FoldOP
do you see it happening in the first one
oh
nope
It's not rerendering
Scottish FoldOP
ok
so im not crazy
@Scottish Fold so im not crazy
I found the issue
the useEffect for registering the service worker
updates on component update (no dep array)
Answer
Scottish FoldOP
yooo
that makes sense
thank you â¤ï¸
and since the effect also updates iframe src at once
it reloads
Scottish FoldOP
yeah
remember to mark an answer as a solution
Scottish FoldOP
just did it
oop
there