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>
);
}