【问题标题】:setInterval in UseEffect getting call 2/4 timesUseEffect 中的 setInterval 被调用 2/4 次
【发布时间】:2022-02-18 16:29:40
【问题描述】:

您好,只想点击 useEffect 一次,但它被调用了 2-3 次,我尝试将函数包装在另一个函数中,但代码开始停止,你们能帮忙

需要调用successHandler,但是它在n over的时候被调用了

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

【问题讨论】:

  • ` const { successHandler } = props; const [完成,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(进度, 500); return () => { clearInterval(timer); }; }, [successHandler]); `
  • 删除 [successHandler] 依赖并将其更改为 [] 如果您只想调用一次。

标签: reactjs react-hooks setinterval use-effect


【解决方案1】:

如果useEffect 被多次调用,则意味着其依赖项中的某些内容发生了变化。在您的情况下,successHandler 发生了变化。看看它来自哪里,也许你需要使用useCallback 来确保它在重新渲染时不会改变。

例如,这将在每次重新渲染时重新运行 useEffect,因为 f 每次都会是一个新函数:

const f = () => {};
useEffect(() => { f(); }, [f]);

虽然这只会运行一次 useEffect,但因为 useCallback 会记住该函数,而 f 在每次重新渲染时都不会改变:

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应该只在完成变为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]);

【讨论】:

  • 我厌倦了它,但它没有发生,因为successHandler正在从useEffect它自己调用,当进度条达到100但它被调用两次时,我也尝试将它从依赖项中删除,但它仍然做同样的事
  • 哦,我想我误解了这个问题。那么useEffect执行了一次,但是successHandler执行了多次?
  • 也许您需要setTimeout 而不是setIntervalsetInterval 应该重复调用 progress 函数,所以这是预期的行为。
  • 或者...我想我现在明白了。您想多次调用 progress,但您希望条件 prevCompleted >= 100 只满足一次。对吗?
  • 是的,你是正确的 sucessHandler 被多次调用
猜你喜欢
  • 2020-10-19
  • 1970-01-01
  • 2021-02-11
  • 2021-11-26
  • 2021-12-27
  • 2021-10-03
  • 2021-08-05
  • 2022-06-12
  • 2023-02-01
相关资源
最近更新 更多