Javascript useInterval和react挂钩问题-无限循环

Javascript useInterval和react挂钩问题-无限循环,javascript,reactjs,loops,react-hooks,intervals,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, se

我有一个骰子组件,我希望它吐出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);
  };
//iter-计算我们呈现一个值的次数
常数[iter,setIter]=useState(0);
//在整个渲染过程中保持给定的有效期
const[intervalId,setIntervalId]=useState(未定义);
//如果iter已达到0,请检查每个渲染(iter更新),以清除间隔
useffect(()=>{
国际热核聚变实验堆{
滚动骰子();
}[道具];
常量rollDice=()=>{
常量间隔=设置间隔(()=>{
//每100ms减少一次iter
设置器((prev)=>prev-1);
}, 100);
//按此间隔运行10次
设置器(10);
setIntervalId(间隔);
};
这是组件返回的内容:

 {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"}
    />
  ))}
{props.values.map((val,i)=>(
))}
但由于某种原因,我得到了一个无限循环,第一个useEffect持续激发。 为什么会发生这种情况?我如何在将来避免这种错误


谢谢。

我认为问题是因为您使用状态来存储局部变量。您调用
setIter
来更新
iter
,但是
setIter
是异步的。因此它不会立即更新,这意味着
iter
可能跳过0并变成负数,如果您只进行检查,负数将是无限的k如果
iter
不同于0。但是如果你检查
iter
大于0,它当然会工作(某种程度上)

您应该将您的
iter
状态替换为ref:

const iter = useRef(0);
然后,您可以使用iter的当前值更新iter:

iter.current = 10;
iter.current--;
然后您的图标代码将为:

icon={dice[iter.current ? Math.floor(Math.random() * 5) : val - 1]}
同样,intervalId不应存储在state中,而应存储在ref中:

const intervalId = useRef();

我现在将iter有效存储在ref中,但我无法将iter存储在ref中,因为每次iter更新时我都需要该组件进行渲染。我现在才注意到无限循环仍在继续,但渲染输出保持不变。但感谢ref的建议,就是这样,该组件不会每次渲染状态
iter
更新,因为
iter
不会在每次调用
setIter
时更新。不仅如此,还不能保证间隔函数会被调用10次。如果确实需要10次,唯一的方法是使用ref。但您可以同时更新另一个状态,并且该状态将用于渲染谢谢你,它成功了,这就是我所做的:,如果这不是你的意思,那么请澄清我做错了什么,但无论如何,现在一切都有意义了,谢谢:)