我正在尝试新的React钩子,并有一个时钟组件,它的时间值应该每秒钟增加。但是,该值不会超过1。

function Clock() { const [time, setTime] = React.useState(0); React.useEffect(() => { const timer = window.setInterval(() => { setTime(time + 1); }, 1000); return () => { window.clearInterval(timer); }; }, []); return ( <div>Seconds: {time}</div> ); } ReactDOM.render(<Clock />, document.querySelector('#app')); <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script> <div id="app"></div>


当前回答

按照下面的操作,它可以正常工作。

const [count , setCount] = useState(0);

async function increment(count,value) {
    await setCount(count => count + 1);
  }

//call increment function
increment(count);

其他回答

原因是传递给setInterval闭包的回调只访问第一次呈现中的时间变量,它不能访问后续呈现中的新时间值,因为第二次没有调用useEffect()。

在setInterval回调函数中,time的值总是0。

与您熟悉的setState一样,状态钩子有两种形式:一种是它接收更新状态的形式,另一种是传递当前状态的回调形式。您应该使用第二种形式,并在setState回调中读取最新的状态值,以确保在增加状态值之前拥有最新的状态值。

好处:可选择的方法 Dan Abramov在他的博客文章中深入讨论了关于使用setInterval和钩子的话题,并提供了解决这个问题的替代方法。强烈推荐阅读!

function Clock() { const [time, setTime] = React.useState(0); React.useEffect(() => { const timer = window.setInterval(() => { setTime(prevTime => prevTime + 1); // <-- Change this line! }, 1000); return () => { window.clearInterval(timer); }; }, []); return ( <div>Seconds: {time}</div> ); } ReactDOM.render(<Clock />, document.querySelector('#app')); <script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script> <div id="app"></div>

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

setInterval的另一个替代方法是在每次状态更新时使用setTimeout设置新的间隔时间:

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

setTimeout对性能的影响很小,一般可以忽略。除非组件对时间敏感,以至于新设置的超时会导致不良影响,否则setInterval和setTimeout方法都是可以接受的。

const [seconds, setSeconds] = useState(0);
  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds((seconds) => {
        if (seconds === 5) {
          setSeconds(0);
          return clearInterval(interval);
        }
        return (seconds += 1);
      });
    }, 1000);
  }, []);

注意:这将有助于使用useState钩子更新和重置计数器。5秒后秒停止。因为首先改变setSecond值,然后在setInterval内用更新的秒停止计时器。as useEffect运行一次。

这个解决方案不为我工作,因为我需要得到变量,做一些事情,而不仅仅是更新它。

我得到了一个变通方法,以获得带有承诺的钩子的更新值

Eg:

async function getCurrentHookValue(setHookFunction) {
  return new Promise((resolve) => {
    setHookFunction(prev => {
      resolve(prev)
      return prev;
    })
  })
}

这样我就可以像这样得到setInterval函数中的值

let dateFrom = await getCurrentHackValue(setSelectedDateFrom);

我从这个博客上抄了代码。所有功劳归于船主。https://overreacted.io/making-setinterval-declarative-with-react-hooks/

唯一的事情是,我把这个React代码改编为React Native代码,所以如果你是一个React Native编码器,只要复制这个,并适应你想要的。很容易适应吧!

import React, {useState, useEffect, useRef} from "react";
import {Text} from 'react-native';

function Counter() {

    function useInterval(callback, delay) {
        const savedCallback = useRef();
      
        // Remember the latest function.
        useEffect(() => {
          savedCallback.current = callback;
        }, [callback]);
      
        // Set up the interval.
        useEffect(() => {
          function tick() {
            savedCallback.current();
          }
          if (delay !== null) {
            let id = setInterval(tick, delay);
            return () => clearInterval(id);
          }
        }, [delay]);
      }

    const [count, setCount] = useState(0);

  useInterval(() => {
    // Your custom logic here
    setCount(count + 1);
  }, 1000);
  return <Text>{count}</Text>;
}

export default Counter;