首页 > 解决方案 > React SetState is ignored

问题描述

I'm trying to make a timer that starts at 1.0 and increases 0.1 until it reaches a random number. You have to start a "session" 5 seconds after the component is rendered and this is all working. The problem is that I want a session to start 5 seconds after another finishes and React ignores the setState that would allow those next sessions and i dont understand why.

Note: It only works if I create a button that calls a toggle function with setIsGameActive(isGameActive => isGameActive = !isGameActive) and click it


const GamePanel = () => {

    const [gameTime, setGameTime] = useState(1);
    const [isGameActive, setIsGameActive] = useState(false);
    const [gameEndTime, setGameEndTime] = useState(0);
    const [lastResults, setLastResults] = useState([]);

    let randomNumber = 0;
    const useFirstTime = useRef({firstTime: true});

    const makeRandomNumber = (min, max) => {
        return min + (max - min) * Math.random()
    }

    const reset = () => {
        setGameTime(1);
        setIsGameActive(false); //ignored
    }

    const gameStart = () => {
        if(useFirstTime.current.firstTime === false){
            if(!isGameActive){
                console.log("Game starting...");
                randomNumber = makeRandomNumber(1.1, 5);
                setGameEndTime(randomNumber.toFixed(1))
                setIsGameActive(true);
            }
        }
    }

    const gameFinished = () => {
        setTimeout(()=>{
            reset();
            gameStart()
        }, 5000)
    }

    useEffect(() => {
        if(useFirstTime.current.firstTime === true){
            useFirstTime.current.firstTime = false;
            setTimeout(() => {
                gameStart();
            }, 5000);
        }
        let interval = null;
        if(isGameActive){
            interval = setInterval(() => {
                if(gameTime.toFixed(1) !== gameEndTime){
                    setGameTime(gameTime => gameTime + 0.1)
                }
                if(gameTime.toFixed(1) === gameEndTime){
                    clearInterval(interval)
                    gameFinished();
                }
            }, 100);
        }else if(!isGameActive && gameTime !== 0){
            clearInterval(interval)
        }
        return () => clearInterval(interval);
    }, [isGameActive, gameTime, gameEndTime, gameStart, gameFinished]);

    return(
        <section id="game-panel">
            <h1></h1>
            <h1>{gameTime.toFixed(1)}x</h1>
        </section>
    );
}

export default GamePanel;

Thanks!!

标签: javascriptreactjs

解决方案


The reset function is created everytime your Component is rendered. Because of this the reset reference inside the timer is different than in the component itself after rerendering. Try to use useCallback for reset to create a memorized version of the function: https://reactjs.org/docs/hooks-reference.html#usecallback

    const reset = useCallback(() => {
        setGameTime(1);
        setIsGameActive(false); //ignored
    },[])


推荐阅读