如何在 REACT 中每分钟为仪表板调用一个 API

IT技术 javascript reactjs
2021-05-25 10:13:13

我在 React 中制作了一个仪表板。它没有主动更新,没有按钮、字段或下拉菜单。它将部署在墙上的电视上以供观看。所有面板(共 9 个)都通过 API 调用更新。初始调用(如下所示)有效,所有 JSON 数据都被提取,仪表板初始更新。

底线问题:我需要在初始调用后每 30 秒到 1 分钟调用一次 API 以检查更新。

我已经尝试在 componentDidMount() 中使用“setInterval”,正如这里回答其他人问题的人所建议的那样,我收到一个错误“await 是一个保留字”。我已经阅读了 forceUpdate() ,考虑到 facebook/react 页面对它的描述,这对我的用例来说似乎是合乎逻辑的。但是,我也在这里阅读以远离那个......

下面的代码是我正在使用的代码的精简版。为简洁起见,我删除了许多组件和导入。任何帮助将不胜感激。

import React, { Component } from 'react';

import Panelone from './Components/Panelone';
import Paneltwo from './Components/Paneltwo';

class App extends Component {

  state = {
      panelone: [],
      paneltwo: []
    }

 async componentDidMount() {
      try {
        const res = await fetch('https://api.apijson.com/...');
        const blocks = await res.json();
        const dataPanelone = blocks.panelone;
        const dataPaneltwo = blocks.paneltwo;

        this.setState({
          panelone: dataPanelone,
          paneltwo: dataPaneltwo,
        })
      } catch(e) {
        console.log(e);
      }

  render () {
    return (
      <div className="App">
        <div className="wrapper">
          <Panelone panelone={this.state} />
          <Paneltwo paneltwo={this.state} />
        </div>
      </div>
    );
  }
}

export default App;
4个回答

将数据获取逻辑移动到一个单独的函数中,并使用setIntervalincomponentDidMount方法调用该函数,如下所示。

  componentDidMount() {
    this.loadData()
    setInterval(this.loadData, 30000);
  }

  async loadData() {
     try {
        const res = await fetch('https://api.apijson.com/...');
        const blocks = await res.json();
        const dataPanelone = blocks.panelone;
        const dataPaneltwo = blocks.paneltwo;

        this.setState({
           panelone: dataPanelone,
           paneltwo: dataPaneltwo,
        })
    } catch (e) {
        console.log(e);
    }
  }

下面是一个工作示例

https://codesandbox.io/s/qvzj6005w

为了使用await,直接封闭它的函数需要是async根据您的说法,如果您想使用setIntervalinside componentDidMount,将 async 添加到内部函数将解决问题。这是代码,

 async componentDidMount() {
          try {
            setInterval(async () => {
              const res = await fetch('https://api.apijson.com/...');
              const blocks = await res.json();
              const dataPanelone = blocks.panelone;
              const dataPaneltwo = blocks.paneltwo;

              this.setState({
                panelone: dataPanelone,
                paneltwo: dataPaneltwo,
              })
            }, 30000);
          } catch(e) {
            console.log(e);
          }
    }

此外,您应该考虑使用 react-timer-mixin,而不是全局使用 setInterval。https://facebook.github.io/react-native/docs/timers.html#timermixin

我想我会加入一种稍微修改的方法,该方法通过功能块内的 setTimeout 调用使用递归。工作原理相同......也许从内部调用函数本身会更简洁,而不是在代码的其他地方执行此操作?

这篇文章更深入地解释了推理……但我一直在将这种方法用于工作中的几个仪表板 - 完成工作!

看起来像这样:

class MyComponent extends React.Component
//create the instance for your interval
intervalID;
constructor(props) {
    super(props);
    this.state = {
        data: [],
        loading: false,
        loadingMap: false,

        //call in didMount...
        componentDidMount() {
          this.getTheData()
        }

 getTheData() {
 //set a loading state - good practice so you add a loading spinner or something
   this.setState({loading: true}), () => {
 //call an anonymous function and do your data fetching, then your setState for the data, and set loading back to false
   this.setState({
       data: fetchedData,
       loading: false
       )}     }
 //Then call the function again with setTimeout, it will keep running at the specified //interval...5 minutes in this case
            this.intervalID = setTimeout(
              this.getTheData.bind(this),
              300000
            );

          }
        }
        //Important! Be sure to clear the interval when the component unmounts! Your app might crash without this, or create memory leaks!
        componentWillUnmount() {
          clearTimeout(this.intervalID);
        }

对不起,如果格式有点偏离。还没有用 Hooks 尝试过这个,但我认为你在 useEffect 调用中会有类似的实现?有没有人这样做过?

我已经看到了很多与此相关的并发症。不需要在生命周期或状态或Promise中拥有它。在这里,服务 api 只是一个简单的 axios api 调用

这是我的完整实现,因为我将它与上下文 api 一起使用(省略了一些私有代码)。就我而言,我只关心 api 中的状态响应,因为我知道我需要更改什么。但是 api 可以是您真正需要的任何数据/从数据方面。

    export class MyContextApiComponent ..... {
    private timeout: ReturnType<typeof setInterval> | undefined
    ...
    ...
    ...
    public statsPolling = (S_UUID: string) => {
        if (!this.timeout) {
            this.timeout = setInterval( () => { 
                this.statsPolling(S_UUID)
            }, 3000)
        }

        this.state.api.StatisticsService.statsPolling(S_UUID)
            .then(res => {
                if (res.hasDescStats) {
                    clearInterval(this.timeout)
                    
                    this.setState(prevState => ({
                        ...prevState,
                        ...
                        ...
                    }))
                }
            })
            .catch(e => console.warn('', e))
    }
   ...
   ...
}

/// in another file in service is the api call itself with axios just checking on the server reply status

export class Statistics implements IStatistics {
    public statsPolling: StatsPolling = async S_UUID => {
        return axios
            .get<{ hasDescStats: boolean }>(`/v2/api/polling?query=${S_UUID}`)
            .then(res => {
                if (res.status === 200) {
                    return { hasDescStats: true }
                } else {
                    return { hasDescStats: false }
                }
            })
    }
}