useInterval和react钩子的问题--无限循环。

问题描述 投票:0回答:1

我有一个骰子组件,我想让它吐出随机值n次,然后显示一个静态值,这应该在每次道具更新时发生。

  //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一直在发射。为什么会发生这种情况,我如何才能在将来避免这种错误?

为什么会出现这种情况,以后如何避免这种错误?

javascript reactjs loops react-hooks intervals
1个回答
1
投票

我认为问题在于你使用状态来存储局部变量。你调用了 setIter 更新 itersetIter 是异步的。所以它不会立即更新,这意味着 iter 可能会跳过0,进入负数,这将是无限的,如果你只是检查是否有 iter 当然,如果你检查一下 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();
© www.soinside.com 2019 - 2024. All rights reserved.