Search code examples
reactjsreact-nativereact-componentreact-contextreact-functional-component

Call API Every X Seconds in React Function Component


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


Solution

  • One issue here is that this.getEndpoint will not work from a function component. It seems the original Alerts class component is missing some code since that must be implemented somewhere.

    Another issue is that the interval is not being cleaned up - you should return a cleanup function from the effect body to clear the timer.

    Lastly there's no reason to re-define getAlerts on every render, defining it once inside of the effect body would be better.

    After cleaning up some missing parens, etc. my final implementation would look something like:

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