在 React 函数组件中每隔 X 秒调用 API

Call API Every X Seconds in React Function Component

我有以下反应 class 组件每 10 秒调用一次 API。它的工作没有问题。

class Alerts extends Component {
  constructor() {
    this.state = {
      alerts: {},
    }
  }

  componentDidMount() {
    this.getAlerts()
    this.timerId = setInterval(() => this.getAlerts(), 10000)
  }

  componentWillUnmount() {
    clearInterval(this.timerId)
  }

  getAlerts() {
    fetch(this.getEndpoint('api/alerts/all"))
        .then(result => result.json())
        .then(result => this.setState({ alerts: result }))
  }

  render() {
    return (
      <>
        <ListAlerts alerts={this.state.alerts} />
      </>
    )
  }
}

我正在尝试将其转换为 React 功能组件。这是我目前的尝试。

const Alerts = () => {

    const [alerts, setAlerts] = useState([])

    useEffect(() => {
        getAlerts()
        setInterval(() => getAlerts(), 10000)
    }, [])

    getAlerts() {
        fetch(this.getEndpoint('api/alerts/all"))
            .then(result => result.json())
            .then(result => setAlerts(result)
    }

    return (
      <>
        <ListAlerts alerts={alerts} />
      </>
    )
}

有人可以帮我完成这个例子吗? useEffect 是正确的用法还是有更好的选择?

如有任何帮助,我们将不胜感激

这里的一个问题是 this.getEndpoint 在功能组件中不起作用。似乎原始 Alerts class 组件缺少一些代码,因为必须在某处实现这些代码。

另一个问题是间隔没有被清理——你应该return一个来自效果体的清理函数来清除计时器。

最后,没有理由在每个渲染器上重新定义 getAlerts,在效果体内定义一次会更好。

在清理了一些丢失的括号等之后,我的最终实现看起来像:

function getEndpoint(path) {
   return ...; // finish implementing this
}


const Alerts = () => {

    const [alerts, setAlerts] = useState([])

    useEffect(() => {
        function getAlerts() {
          fetch(getEndpoint('api/alerts/all'))
            .then(result => result.json())
            .then(result => setAlerts(result))
        }
        getAlerts()
        const interval = setInterval(() => getAlerts(), 10000)
        return () => {
          clearInterval(interval);
        }
    }, [])

    return (
      <>
        <ListAlerts alerts={alerts} />
      </>
    )
}

我找到了 Dan Abramov 的 this blog,它解释了 useInterval 钩子解决这个问题的想法。 你可以这样使用它:

function Counter() {
  useInterval(() => {
    callMyApi()
  }, 1000);
}

并以这种方式声明 useInterval 挂钩:

import React, { useState, useEffect, useRef } from 'react';

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

  // Remember the latest callback.
  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]);
}

希望对大家有所帮助!