I'm using the CircularProgress component from material-ui and my own component that animates the circular progress icon using setInterval. After each interval, the progress icon redraws. When the circle closes, it resets -and- it attempts to notify the parent using a callback prop.
This design produces the well understood warning,
Warning: Cannot update a component (
App
) while rendering a different component (RefreshTimer
).
But I have not seen a solution when setInterval() is used. In the below case, the timer has two jobs that impact both the parent and the child. Yes, I can elevate the timer to the parent, but I suspect there is a better solution and good opportunity for me to learn something.
Code fragments...
App component:
export default function App() {
const [refreshFlag, setRefreshFlag] = useState(false);
const handleRefresh = useCallback(() => {
setRefreshFlag(!refreshFlag);
console.log('setting refresh flag?!?');
}, [refreshFlag]);
useEffect(() => {
console.log('trigger App refresh!');
}, [refreshFlag]);
return(<div>
<RefreshTimer handleRefresh={handleRefresh}/>
</div>)
}
RefreshTimer component:
export default function RefreshTimer({handleRefresh}) {
const [progress, setProgress] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setProgress((prevProgress) => {
if( prevProgress >= 100 ) {
handleRefresh(true);
return 0;
} else {
return prevProgress + 10;
}
});
}, (REFRESH_RATE*1000/10));
return () => {
clearInterval(timer);
};
});
return <CircularProgressWithLabel value={progress} />;
}
The use of handleRefresh()
inside of useEffect() of the child produces the warning since it causes App to re-render.
What is the right design pattern for using setInterval in a child component like this?