SetInterval没有显示更新状态

时间:2019-08-13 11:19:17

标签: javascript reactjs setinterval react-hooks

在调用setInterval函数之前,我已将状态设置为true。但是,即使useEffect钩子是由状态的新值触发的,也没有反映在setInterval函数中。

enter image description here 此处的代码沙箱:https://jsfiddle.net/6e05tc2L/3/

let interval;
const Component = () => {
  React.useEffect(() => {
    console.log('State updated to', state);
  });
  const [state, setState] = React.useState(false);
  const on = () => {
    setState(true);
    interval = setInterval(() => {
      console.log(state);
    }, 1000);
    }
  const off = () => {
    setState(false);
    clearInterval(interval);
  }
  const toggle = () => state ? off() : on()

  return (<div>
    <button onClick={toggle}>Toggle State</button>
   </div>);
}

ReactDOM.render(
  <Component />,
  document.getElementById('container')
);

一旦更新,就不应该使用新的state值吗?

4 个答案:

答案 0 :(得分:3)

传递给useEffect的函数内部的值在每个渲染器上都会刷新,因为useEffect使用了传递给它的函数的新定义。

但是传递给setInterval的函数只定义了一次,它关闭了状态的旧值。尚未更新。

使用钩子进行闭包是很棘手的,但是要意识到的是useEffect为每个渲染创建了一个新函数,因此每次函数关闭一个新的状态值时都会创建一个新函数。

然后,诀窍是在useEffect自身内部调用与setInterval相关的代码,该函数本身取决于state的变化值

React.useEffect(() => {
  if(state) {

    interval = setInterval(() => {
      console.log(state);
    }, 1000);
  } else {
    clearInterval(interval);
  }

}, [state]);

或者更好的是,使用useInterval挂钩为您处理这些详细信息。

答案 1 :(得分:1)

setInterval始终可以访问组件的 first 呈现器的值,因为传递给setInterval的函数会围绕该值闭合,并且不会被重新声明。您可以使用自定义钩子解决此问题:

function useInterval(callback, delay) {
  const savedCallback = useRef();

  useEffect(() => {
    savedCallback.current = callback;
  });

  useEffect(() => {
    function tick() {
      savedCallback.current();
    }

    let id = setInterval(tick, delay);
    return () => clearInterval(id);
  }, [delay]);
}

该实现和对React Hooks与setInterval之间不匹配的详尽解释是来自React贡献者之一的丹·阿布拉莫夫Making setInterval Declarative with React Hooks

答案 2 :(得分:0)

如果您希望在状态更改时重新加载组件,则应像这样创建useEffect。

Array ( 
    [mode] => isu 
    [merchantId] => DEMOPAYPAL 
    [merchantIdInPayPal] => *********** 
    [permissionsGranted] => true 
    [consentStatus] => true 
    [productIntentId] => addipmt 
    [isEmailConfirmed] => true 
    [accountStatus] => BUSINESS_ACCOUNT 
)

您创建的方式与React.useEffect(() => { console.log('State updated to', state); }, [state]); 相同,只是将数组作为第二个参数,就像componentDidMount()一样,它具有依赖性。因此,只要您的状态发生变化,您的组件就会重新呈现。

要解决setTimeout的无穷大调用,您可以在创建函数的地方进行

componentDidUpdate()

使用此React会知道您只想创建一次此功能。

答案 3 :(得分:0)

我不是ReactJS专家,但是我猜您正在记录的React.useCallback(() => { setInterval(() => { console.log(state); }, 1000); }) 不会刷新,因为它被声明一次且从未刷新过。如果state是为您提供状态的方法,则应在间隔函数中使用它。

以下是我要解释的示例:

React.useState(false)