【问题标题】:React hooks. Periodic run useEffect反应钩子。周期性运行使用效果
【发布时间】:2020-04-27 06:05:26
【问题描述】:

我需要定期获取数据并将其更新到屏幕上。 我有这个代码:

const [temperature, setTemperature] = useState();

useEffect(() => {

fetch("urlToWeatherData")
  .then(function(response) {
     if (response.status !== 200) {
      console.log(
        "Looks like there was a problem. Status Code: " + response.status
      );
      return;
    response.json().then(function(data) {
     console.log(data[0].temperature);
     setTemperature(data[0].temperature);

    });
  })
  .catch(function(err) {
    console.log("Fetch Error :-S", err);
  });
 }, []  );

那么,例如,是否有任何巧妙的方法可以每 15 秒运行一次? 谢谢!

【问题讨论】:

    标签: javascript reactjs react-hooks setinterval use-effect


    【解决方案1】:

    将其包装在一个区间中,并且在组件卸载时不要忘记返回一个拆卸函数以取消该区间:

    useEffect(() => {
      const id = setInterval(() => 
        fetch("urlToWeatherData")
          .then(function(response) {
             if (response.status !== 200) {
              console.log(
                "Looks like there was a problem. Status Code: " + response.status
              );
              return;
            response.json().then(function(data) {
             console.log(data[0].temperature);
             setTemperature(data[0].temperature);
            });
          })
          .catch(function(err) {
            console.log("Fetch Error :-S", err);
          });
      ), 15000);
    
      return () => clearInterval(id);  
    }, []);
    

    【讨论】:

    • 只是一个补充说明,如果你想立即运行它而不是初始化后 15 秒,只需命名箭头函数,将引用传递给 setInterval(),然后在返回拆卸之前立即调用它。
    • 谢谢大家!我确实将它包装在一个函数中,然后只调用了两次,例如:getData();setInterval(getData, 15000); 现在它似乎完全可以正常工作。
    【解决方案2】:

    只是为了提供一种不同的方法,您可以定义一个自定义挂钩来将此功能提取到可重用函数中:

    const useInterval = (callback, interval, immediate) => {
      const ref = useRef();
    
      // keep reference to callback without restarting the interval
      useEffect(() => {
        ref.current = callback;
      }, [callback]);
    
      useEffect(() => {
        // when this flag is set, closure is stale
        let cancelled = false;
    
        // wrap callback to pass isCancelled getter as an argument
        const fn = () => {
          ref.current(() => cancelled);
        };
    
        // set interval and run immediately if requested
        const id = setInterval(fn, interval);
        if (immediate) fn();
    
        // define cleanup logic that runs
        // when component is unmounting
        // or when or interval or immediate have changed
        return () => {
          cancelled = true;
          clearInterval(id);
        };
      }, [interval, immediate]);
    };
    

    然后你可以像这样使用钩子:

    const [temperature, setTemperature] = useState();
    
    useInterval(async (isCancelled) => {
      try {
        const response = await fetch('urlToWeatherData');
        // check for cancellation after each await
        // to prevent further action on a stale closure
        if (isCancelled()) return;
    
        if (response.status !== 200) {
          // throw here to handle errors in catch block
          throw new Error(response.statusText);
        }
    
        const [{ temperature }] = await response.json();
        if (isCancelled()) return;
    
        console.log(temperature);
        setTemperature(temperature);
      } catch (err) {
        console.log('Fetch Error:', err);
      }
    }, 15000, true);
    

    如果组件被卸载,我们可以通过检查isCancelled()来阻止回调调用setTemperature()。对于useInterval() 的更一般用例,当回调依赖于有状态变量时,您应该更喜欢useReducer() 或至少使用the functional update form of useState()。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-27
      • 2020-12-02
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 2019-08-17
      • 1970-01-01
      相关资源
      最近更新 更多