Hi want to hit useEffect just once, but its happening that its getting called 2-3 times , I tried wrapping the function in another but code starts to brake, can you guys help
need to call successHandler, but it is getting called over n over while it
const { successHandler } = props;
const [completed, setCompleted] = React.useState(10);
const fileType = getFileType(props.fileName);
React.useEffect(() => {
function progress() {
setCompleted(prevCompleted => {
if (prevCompleted >= 100) {
successHandler();
return 100;
}
return prevCompleted + 10; });
}
const timer = setInterval(progress, 500);
return () => { clearInterval(timer); };
}, [successHandler]);
If useEffect
is called multiple times, then it means that something in its dependencies changes. In your case successHandler
changes. See where it comes from, maybe you need to use useCallback
for it to make sure it doesn't change on re-render.
For example this will re-run useEffect
on each re-render, because f
will be a new function each time:
const f = () => {};
useEffect(() => { f(); }, [f]);
While this will run useEffect
only once, since useCallback
memoizes the function and f
will not change on each re-render:
const f = useCallback(() => {}, []);
useEffect(() => { f(); }, [f]);
Later edit - I missunderstood the question. Try to rewrite it like this:
const { successHandler } = props;
const [completed, setCompleted] = React.useState(10);
const fileType = getFileType(props.fileName);
React.useEffect(() => {
function progress() {
setCompleted(prevCompleted => Math.max(100, prevCompleted + 10));
}
const timer = setInterval(progress, 500);
return () => {
clearInterval(timer);
};
}, []);
React.useEffect(() => {
if (completed === 100) {
successHandler();
}
}, [completed, successHandler]);
This way successHandler
should only be called once when completed becomes 100 (given that successHandler does not change).
You probably want to stop the time when progress is 100 too, so you can do it like this:
const { successHandler } = props;
const [completed, setCompleted] = React.useState(10);
const fileType = getFileType(props.fileName);
const timer = React.useRef(null);
const stopTimer = React.useCallback(() => {
if (timer.current) {
clearInterval(timer.current);
timer.current = null;
}
}, []);
React.useEffect(() => {
function progress() {
setCompleted(prevCompleted => Math.max(100, prevCompleted + 10));
}
timer.current = setInterval(progress, 500);
return stopTimer;
}, [stopTimer]);
React.useEffect(() => {
if (completed === 100) {
stopTimer();
successHandler();
}
}, [completed, stopTimer, successHandler]);