Home > Software engineering >  How to keep calling api until task is completed in reactjs?
How to keep calling api until task is completed in reactjs?

Time:01-02

I am working on reactjs as frontend, and Django in the backend. I have a time taking task written in django, which ideally takes more time to retrieve values than the stipulated API response time. Therefore, I have made it into a celery task, whose task id I return as an API response.

The plan was to make the API call on page load which starts the celery task, and returns the task ID. So, with the task ID, I can keep polling another API to get the task's status, until completed. Once the task is completed, I can ping another API to get the response of the celery task.

I thought, I can make the API call, and thenafter run a loop with a sleep, but not sure how to achieve this?

import { useEffect, useState } from "react"
import axios from "axios"

function App() {
  const [taskId, setTaskId] = useState("")
  
  const apiToSpawnTask = () => {
    axios.get("http://localhost:8000/spawn_task")
      .then(({data}) => setTaskId(data.task_id))
  }

  const checkTaskStatus = () => {
    axios.get(`http://localhost:8000/task-id/${taskId}`)
      .then(({data}) => {
       // data.status contains the status of the task id
    })
  }

  const getCompletedTaskResult = () => {
    axios.get(`http://localhost:8000/get-task-result/${taskId}`)
      .then(({data}) => {
      // this data is used in the return
    })
  }

  useEffect(() => {
    // What should be the code here?
  })

  return (<div>Test</div>)
}

CodePudding user response:

const checkTaskStatus = () => {
  return axios.get(`http://localhost:8000/task-id/${taskId}`)
    .then(({data}) => {
      return data
    })
}
// ...
useEffect(() => {
  const interval = setInterval(() => {
    const status = checkTaskStatus
    // probably a different property returned from your api
    if (status.ready) {
      clearInterval(interval)
    }
  }, 1000)

  return () => clearInterval(interval)
})

CodePudding user response:

import { useEffect, useState, useRef } from "react"
import axios from "axios"

function App() {
  const [taskId, setTaskId] = useState("");
  const intervalRef = useRef(null);

  const apiToSpawnTask = () => {
    axios.get("http://localhost:8000/spawn_task")
      .then(({data}) => {
        setTaskId(data.task_id);
        intervalRef.current = setInterval(() => {
          checkTaskStatus(data.task_id);
        }, 5000);
       })
  }

  const checkTaskStatus = (id) => {
    axios.get(`http://localhost:8000/task-id/${id}`)
      .then(({data}) => {
       // data.status contains the status of the task id
       if(data.status === 'success') {
          getCompletedTaskResult();
          clearInterval(intervalRef.current);
       }
    })
  }

  const getCompletedTaskResult = () => {
    axios.get(`http://localhost:8000/get-task-result/${taskId}`)
      .then(({data}) => {
      // this data is used in the return
    })
  }

  useEffect(() => {
    apiToSpawnTask();
  }, [])

  return (<div>Test</div>)
}

Tip: instead of hardcoding the base URL as http://localhost:8000, try to use axios instance for that. So if you want to change base URL in future, you don't need to modify everywhere.

axios/index.js

import axios from "axios";
const instance = axios.create({
  baseURL: "http://localhost:8000"
});
export default instance;

  • Related