Search code examples
javascriptreactjsuse-effectuse-statesetstate

Why does useEffect only working properly once?


I'm having big problems that are getting me hella confused with React useEffect & States.

I have this following component, everything in it looks to work normally until I redirect to my app main page and try it again. The problem is that the useEffect is triggered once and do not work anymore even if the server is sending infos correctly as I already Tested. Going to show a video for example

const GameComponent = function(props) {
    const [selectedHand, setSelectedHand] = useState('random')
    const [isGameReady, setIsGameReady] = useState(false)
    const [gameStep, setGameStep] = useState(0)
    let listenersStarted = useRef(false)
    function currentSelector(e){
        setSelectedHand(e.currentTarget.getAttribute('value'));
    }


    function getSelectedHand(value) {

        if (value === selectedHand) {
            return "box3 selected";
        }
        return "box3";
    }


    useEffect(() => {
        const serverInteractions = {

            sendChoice: ()=>{
                props.server.emit("choice", selectedHand)
            },

            startListeners: ()=>{

                props.server.emit("game status")
                if (!listenersStarted.current){
                    if (!props.server.hasListeners('game status')){
                        props.server.on('game status', async args=>{
                            await new Promise(r => setTimeout(r, 250));
                            document.getElementById('instruction').textContent = args['status']
                            setIsGameReady(args['isReady'])
                        })

                        props.server.on('game result', async ()=>{
                            await new Promise(r => setTimeout(r, 250));
                        })

                    }
                    listenersStarted.current = true
                }
            }
        }

        serverInteractions.startListeners()

    }, []);



    useEffect(() => {
        console.log(isGameReady, gameStep)
        if (isGameReady && gameStep===0){
            setGameStep(1)
        }else if(!isGameReady && gameStep>0){
            setGameStep(0)
        }
    }, [isGameReady]);
    useEffect( () => {

        const asyncFunction = async ()=>{

            if(!isGameReady && gameStep >0){
                await setGameStep(0)
            }else if (isGameReady){
                console.log(gameStep, isGameReady)
                if (isGameReady && gameStep === 1){
                    document.getElementById('instruction').textContent = ""
                    const oldGameStep = gameStep
                    await new Promise(r => setTimeout(r, 5000));

                    if (isGameReady && oldGameStep == gameStep){
                        await setGameStep(2)

                    }
                }else if(isGameReady && gameStep === 2){
                    console.log('mandando resultado')
                    //await serverInteractions.sendChoice()
                    document.getElementById('instruction').textContent = ""


                }else if(isGameReady && gameStep===3){
                    console.log(isGameReady)
                    if (isGameReady){
                        console.log(isGameReady)
                        document.getElementById('instruction').textContent = ""
                        setSelectedHand('random');
                        await new Promise(r => setTimeout(r, 5000));
                        if (isGameReady){
                            await setGameStep(0)

                        }
                    }

                }else if(isGameReady && gameStep===0){
                    await setGameStep(1)

                }

            }

        }
        asyncFunction()
    }, [gameStep]);

Video: https://i.sstatic.net/8oGfz.jpg

Video 2 ( With more server informations ) https://i.sstatic.net/qm00v.jpg

As you can see In this video, I do the step by step until I get the problem. First I join into a room then the useEffect seems to work normally but when trying again after a SPA redirect to the main page and doing the same thing it stops working, only triggering once. I'm sure that the server is sending the same infos correctly, and don't see many reasons to it not work ( the gameIsReady is a boolean value, and the server is returning false/true )

This is the highlight of useEffect:

    useEffect(() => {
        console.log(isGameReady, gameStep)
        if (isGameReady && gameStep===0){
            setGameStep(1)
        }else if(!isGameReady && gameStep>0){
            setGameStep(0)
        }
    }, [isGameReady]);

And this is were setState is used:

props.server.on('game status', async args=>{
                            await new Promise(r => setTimeout(r, 250));
                            document.getElementById('instruction').textContent = args['status']
                            setIsGameReady(args['isReady'])
                        })

Already tried: Adding isReady and gameStep to dependencies


Solution

  • De-registering your socket.io listeners is the answer.