useInterval和React挂钩问题-无限循环

时间:2020-04-25 17:04:58

标签: javascript reactjs loops react-hooks intervals

我有一个骰子组件,我希望它吐出n次随机值,然后显示一个静态值,并且每次更新道具时都会发生这种情况。所以我在以下代码中使用了setInterval:

  //iter - keep count on how many times we rendered a value
  const [iter, setIter] = useState(0);

  //keep the intervalId given throughout the renderes
  const [intervalId, setIntervalId] = useState(undefined);

  //check each render(iter update) if iter has reached 0, to clear the interval
  useEffect(() => {
    if (iter <= 0) {
      clearInterval(intervalId);
    }
  }, [iter]);

  //if the props updated, call roll dice
  useEffect(() => {
    rollDice();
  }, [props]);

  const rollDice = () => {
    const interval = setInterval(() => {
      //reduce iter every 100ms
      setIter((prev) => prev - 1);
    }, 100);

    //run this interval 10 times
    setIter(10);
    setIntervalId(interval);
  };

这是组件返回的内容:

 {props.values.map((val, i) => (
    <FontAwesomeIcon
      key={i}
      //randomize icons
      icon={dice[iter ? Math.floor(Math.random() * 5) : val - 1]}
      size={props.size || "4x"}
      color={props.color || "white"}
    />
  ))}

但是由于某种原因,我遇到了无限循环,第一个useEffect不断触发。 为什么会发生这种情况?将来如何避免这种错误?

谢谢。

1 个答案:

答案 0 :(得分:1)

我认为问题是因为您使用状态来存储局部变量。您调用setIter来更新iter,但是setIter是异步的。因此它不会立即更新,这意味着iter可能会跳过0并进入负数,如果仅检查iter是否不同于0,则该数将是无限的。但是,它当然可以工作(排序of),如果您检查iter大于0。

您应将iter状态替换为参考:

const iter = useRef(0);

然后您可以使用其当前值来更新iter:

iter.current = 10;
iter.current--;

那么您的图标代码将是:

icon={dice[iter.current ? Math.floor(Math.random() * 5) : val - 1]}

同样,intervalId不应以状态存储,而应存储在ref中:

const intervalId = useRef();