Home > Mobile >  Infinite loop rerender react
Infinite loop rerender react

Time:05-26

I have faced the problem of infinite rerender after checkColor is true I setIsCorrect to true and let the child component call handleCorrectAnswer to setIsCorrect to false after resetting the Clock Why I got an infinite loop?

This is main component on update function I receive data from firebase and when the data in firebase match the current color that I generated I want to reset clock

import { Typography } from '@mui/material';
import React, { useEffect, useState } from 'react';
import CountdownTimer from './CountdownTimer';
import ColorBox from './ColorBox';
import app from '../utils/firebase';
import { getDatabase, ref, onValue } from 'firebase/database';

function genColor() {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);

    return { r, g, b };
}

function checkColor(color1, color2) {
    const { r: r1, g: g1, b: b1 } = color1;
    const { r: r2, g: g2, b: b2 } = color2;
    const diffR = Math.abs(r1 - r2);
    const diffG = Math.abs(g1 - g2);
    const diffB = Math.abs(b1 - b2);
    return diffR < 25 && diffG < 25 && diffB < 25;
}

export default function Game() {
    const [isCorrect, setIsCorrect] = useState(false);
    const [colorFromUser, setColorFromUser] = useState({ r: 0, g: 0, b: 0 });
    const [gameColor, setGameColor] = useState({ r: 300, g: 300, b: 300 });
    const [timestamp, setTimestamp] = useState(0);

    if (checkColor(colorFromUser, gameColor)) {
        setIsCorrect(true);
    }

    function handleCorrectAnswer() {
        setIsCorrect(false);
        console.log('correct');
        const newColor = genColor();
        setGameColor((prevState) => {
            return { ...prevState, ...newColor };
        });
    }

    function update() {
        var userId = 'XJI27hbv5eVmvEXTaCJTQnhZ33C2';
        const dbRef = ref(getDatabase(app));

        onValue(dbRef, function(snapshot) {
            const data = snapshot.val().UsersData[userId].readings;

            const dataColor = data.data.split(' ');
            console.log(dataColor);
            setColorFromUser((prevState) => ({
                ...prevState,
                r: Number(dataColor[0]),
                g: Number(dataColor[1]),
                b: Number(dataColor[2]),
            }));
            setTimestamp(data.timestamp);
        });
    }

    useEffect(() => {
        update();
        handleCorrectAnswer();
    }, []);

    return (
        <div className="main-container">
            <div className="main">
                <div className="current-color">
                    <ColorBox
                        color={`rgb(${gameColor.r}, ${gameColor.g}, ${gameColor.b})`}
                    />
                    <CountdownTimer
                        isCorrect={isCorrect}
                        handleCorrectAnswer={handleCorrectAnswer}
                        setIsCorrect={setIsCorrect}
                    />
                </div>
            </div>
        </div>
    );
}

This is clock component that I want to reset in onComplete method

export default function CountdownTimer(props) {
    const [key, setKey] = useState(0);
    return (
        <div className="timer">
            <CountdownCircleTimer
                key={key}
                onComplete={() => {
                    console.log('done');
                    return { shouldRepeat: true, delay: 2 };
                }}
                onUpdate={(remainingTime) => {
                    if (props.isCorrect) {
                        setKey((prevKey) => prevKey   1);
                        console.log('update');
                        props.handleCorrectAnswer();
                    }
                    console.log(remainingTime);
                }}
                size={130}
                isPlaying
                duration={60}
                colors="#C18FEE"
            >
                {({ remainingTime, color }) => (
                    <Typography sx={{ color, fontSize: 40 }}>
                        {remainingTime}
                    </Typography>
                )}
            </CountdownCircleTimer>

        </div>
    );
}

CodePudding user response:

Move this to useEffect:

if (checkColor(colorFromUser, gameColor)) {
        setIsCorrect(true);
    }

It should be

import { Typography } from '@mui/material';
import React, { useEffect, useState } from 'react';
import CountdownTimer from './CountdownTimer';
import ColorBox from './ColorBox';
import app from '../utils/firebase';
import { getDatabase, ref, onValue } from 'firebase/database';

function genColor() {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);

    return { r, g, b };
}

function checkColor(color1, color2) {
    const { r: r1, g: g1, b: b1 } = color1;
    const { r: r2, g: g2, b: b2 } = color2;
    const diffR = Math.abs(r1 - r2);
    const diffG = Math.abs(g1 - g2);
    const diffB = Math.abs(b1 - b2);
    return diffR < 25 && diffG < 25 && diffB < 25;
}

export default function Game() {
    const [isCorrect, setIsCorrect] = useState(false);
    const [colorFromUser, setColorFromUser] = useState({ r: 0, g: 0, b: 0 });
    const [gameColor, setGameColor] = useState({ r: 300, g: 300, b: 300 });
    const [timestamp, setTimestamp] = useState(0);

    

    function handleCorrectAnswer() {
        setIsCorrect(false);
        console.log('correct');
        const newColor = genColor();
        setGameColor((prevState) => {
            return { ...prevState, ...newColor };
        });
    }

    function update() {
        var userId = 'XJI27hbv5eVmvEXTaCJTQnhZ33C2';
        const dbRef = ref(getDatabase(app));

        onValue(dbRef, function(snapshot) {
            const data = snapshot.val().UsersData[userId].readings;

            const dataColor = data.data.split(' ');
            console.log(dataColor);
            setColorFromUser((prevState) => ({
                ...prevState,
                r: Number(dataColor[0]),
                g: Number(dataColor[1]),
                b: Number(dataColor[2]),
            }));
            setTimestamp(data.timestamp);
        });
    }

    useEffect(() => {

         if (checkColor(colorFromUser, gameColor)) {
        setIsCorrect(true);
    }
        update();
        handleCorrectAnswer();
    }, []);

    return (
        <div className="main-container">
            <div className="main">
                <div className="current-color">
                    <ColorBox
                        color={`rgb(${gameColor.r}, ${gameColor.g}, ${gameColor.b})`}
                    />
                    <CountdownTimer
                        isCorrect={isCorrect}
                        handleCorrectAnswer={handleCorrectAnswer}
                        setIsCorrect={setIsCorrect}
                    />
                </div>
            </div>
        </div>
    );
}
  • Related