如何映射数组,并使用react-hooks更改状态异步

时间:2019-10-28 12:15:53

标签: reactjs react-hooks

我希望组件每5秒重新渲染一次并在相应的索引处显示该数组,已知数组长度恰好是10。

这是我到目前为止所做的:

const GameCard = ({ gameArray, startGame }) => {

  const [arrayIndex, setArrayIndex] = useState(0);
  let {questionWord} = gameArray[arrayIndex] ;

  useEffect(() => {

      if(!startGame) return;

      let timer = setTimeout(() => {
        if(arrayIndex === 9) return; //is this valid ?
        setArrayIndex(arrayIndex +1)} , 1500)

      return () => {
          clearTimeout(timer)
      }
  }, [arrayIndex ,startGame]);

  return (<div>{questionWord}</div>)

startGame是一个布尔属性,用户点击后就会更改。

现在,这是可行的,但是您可以看到即时消息基于2个变量触发了useEffect,当我到达数组末尾时,我将在setTimeout内部返回,以防止arrayIndex更新。

这感觉很hack,如何改善异步useEffect? 从setTimeout函数或useEffect返回时会发生什么?

1 个答案:

答案 0 :(得分:1)

setArrayIndex((i) => i + 1)这样使用functional updates可能很诱人:

  

如果新状态是使用先前状态计算的,则可以将函数传递给setState。

但是,您的代码需要使用arrayIndex常量的原始值,即,如果在注册0时它是setTimeout,则希望它是{{1 }},甚至在5秒钟后。

您的代码中已经存在这种情况-在不同的渲染器中它会有所不同(每个计时器将具有不同的值,因为它是在不同的渲染器中注册的),但是该值在计时器的注册和执行之间不会改变(参见Closures)。


至于改进,甚至可以在注册新的setTimeout之前检测到0,如下所示:

arrayIndex === 9

此外,如果您希望计时器减少渲染时间(即,每次渲染后不是5秒,而是5秒间隔),则需要mutable reference而不是不可变状态:

useEffect(() => {
  if(!startGame || arrayIndex >= 9) return

  const timer = setTimeout(() => {
    setArrayIndex(arrayIndex + 1)
  }, 5000)
  return () => clearTimeout(timer)
}, [arrayIndex, startGame])