UseEffect 中的 setInterval 获得调用 2/4 次
setInterval in UseEffect getting call 2/4 times
嗨,我只想点击一次 useEffect,但它被调用了 2-3 次,我尝试将函数包装在另一个函数中,但代码开始中断,你们能帮忙吗
需要调用 successHandler,但是它被调用了 n 次
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]);
如果useEffect
被多次调用,则意味着其依赖项中的某些内容发生了变化。在你的情况下 successHandler
发生了变化。查看它的来源,也许您需要使用 useCallback
来确保它不会在 re-render.
上发生变化
例如,这将在每个 re-render 上 re-run useEffect
,因为 f
每次都是一个新函数:
const f = () => {};
useEffect(() => { f(); }, [f]);
虽然这只会 运行 useEffect
一次,因为 useCallback
记忆函数并且 f
不会在每个 re-render 上改变:
const f = useCallback(() => {}, []);
useEffect(() => { f(); }, [f]);
稍后编辑 - 我误解了这个问题。尝试像这样重写它:
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]);
这种方式 successHandler
应该只在 completed 变成 100 时调用一次(假设 successHandler 没有改变)。
你可能也想在进度为 100 时停止计时,那么你可以这样做:
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]);
嗨,我只想点击一次 useEffect,但它被调用了 2-3 次,我尝试将函数包装在另一个函数中,但代码开始中断,你们能帮忙吗
需要调用 successHandler,但是它被调用了 n 次
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]);
如果useEffect
被多次调用,则意味着其依赖项中的某些内容发生了变化。在你的情况下 successHandler
发生了变化。查看它的来源,也许您需要使用 useCallback
来确保它不会在 re-render.
例如,这将在每个 re-render 上 re-run useEffect
,因为 f
每次都是一个新函数:
const f = () => {};
useEffect(() => { f(); }, [f]);
虽然这只会 运行 useEffect
一次,因为 useCallback
记忆函数并且 f
不会在每个 re-render 上改变:
const f = useCallback(() => {}, []);
useEffect(() => { f(); }, [f]);
稍后编辑 - 我误解了这个问题。尝试像这样重写它:
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]);
这种方式 successHandler
应该只在 completed 变成 100 时调用一次(假设 successHandler 没有改变)。
你可能也想在进度为 100 时停止计时,那么你可以这样做:
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]);