8

I have the following react class component to call an API every 10 seconds. Its works with no issues.

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} />
      </>
    )
  }
}

I am trying covert this to a react functional component. This is my attempt so far.

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} />
      </>
    )
}

Please can someone help me complete the example? Is useEffect the correct usage or is there a better option?

Any help would be appreciated

4

2 回答 2

12

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

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

最后,没有理由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} />
      </>
    )
}
于 2019-12-02T21:21:59.900 回答
11

我找到了 Dan Abramov 的博客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]);
}

希望它可以帮助某人!

于 2020-07-08T15:31:19.467 回答