在 Set间隙中使用 "反应状态" 挂钩时状态不更新

共4个回答,已解决, 标签: javascript reactjs react-hooks

我正在尝试新的反应钩,并有一个时钟组件与计数器, 这应该是增加每一秒钟。但是, 该值不会超过 1。

function Clock() {
  const [time, setTime] = React.useState(0);
  React.useEffect(() => {
    const timer = window.setInterval(() => {
      setTime(time + 1);
    }, 1000);
    return () => {
      window.clearInterval(timer);
    };
  }, []);

  return (
    Seconds: {time}
  );
}

ReactDOM.render(, document.querySelector('#app'));
第1个答案(采用)

原因是, 注入到 setInterval 闭包中的回调只访问 time 第一次呈现中的变量, 因此它无法访问 time 后续呈现中的新值 useEffect() , 因为第二次未调用该值。

time回调中始终具有 0 的值 setInterval

setState 您熟悉的状态挂钩一样, 状态挂钩有两种形式: 一种是在更新状态中使用的形式, 另一种是传递当前状态的回调形式。您应该使用第二个窗体并读取回调中的最新状态值, setState 以确保在递增之前具有最新的状态值。

奖金: 替代方法

丹·阿布拉莫夫 setInterval他的博客文章中深入讨论了如何使用钩子的话题, 并提供了解决这个问题的替代方法。强烈推荐阅读它!

function Clock() {
  const [time, setTime] = React.useState(0);
  React.useEffect(() => {
    const timer = window.setInterval(() => {
      <-- change="" this="" line!="" },="" 1000);="" return="" ()=""> {
      window.clearInterval(timer);
    };
  }, []);

  return (
    Seconds: {time}
  );
}
第2个答案

useEffect当提供空输入列表时, 仅在组件装载时计算一次函数。

另一种方法 setIntervalsetTimeout 在每次更新状态时设置新的间隔:

  const [time, setTime] = React.useState(0);
  React.useEffect(() => {
    const timer = setTimeout(() => {
      setTime(time + 1);
    }, 1000);
    return () => {
      clearInterval(timer);
    };
  }, [time]);

对性能的影响 setTimeout 不大, 一般可以忽略。除非组件对新设置的超时会产生不良影响的时间敏感, 否则这两种 setInterval 方法 setTimeout 都是可以接受的。

第3个答案

另一种解决方案是使用 useReducer , 因为它将始终传递到当前状态。

function Clock() {
  const [time, dispatch] = React.useReducer((state = 0, action) => {
    if (action.type === 'add') return state + 1
    return state
  });
  React.useEffect(() => {
    const timer = window.setInterval(() => {
      dispatch({ type: 'add' });
    }, 1000);
    return () => {
      window.clearInterval(timer);
    };
  }, []);

  return (
    Seconds: {time}
  );
}
第4个答案

告诉 "反应" 在时间变的时候重新呈现。选择退出

function Clock() {
  const [time, setTime] = React.useState(0);
  React.useEffect(() => {
    const timer = window.setInterval(() => {
      setTime(time + 1);
    }, 1000);
    return () => {
      window.clearInterval(timer);
    };
  }, [time]);

  return (
    Seconds: {time}
  );
}

相关问题

如何从异步调用返回响应? 循环中的 JavaScript 闭包--简单的实际示例 如何从异步调用返回响应? 如何使用使用效果挂钩注册事件? 未知的浏览器 kaios 在 Set间隙中使用 "反应状态" 挂钩时状态不更新 根据恒定条件调用反应钩是否安全?