Home > Back-end >  How to call an async function in different time intervals and with different arguments
How to call an async function in different time intervals and with different arguments

Time:11-05

My goal is to incrementally increase the progress bar when some time have passed after creating an order. To do this, I'd like to call the updateStatus async function below at different intervals and with different arguments until the progress state reaches 100. Below I've pasted my code bit.

Chaining setTimeOut and Promises resulted in the progress bar increasing and decreasing randomly and causing the app to slow down / freeze. What is the proper way to handle what I'm trying to achieve?

const ProgressBar = ({ order }) => {
  const { status, order_date } = order;
  const msTillXSeconds = (seconds) => new Date(moment(order_date).add(seconds, 'seconds')).getTime() - Date.now();

  const [progress, setProgress] = useState(progression[status]);
  const [internalStatus, setInternalStatus] = useState(status);

  const updateStatus = async (newStatus) => {
    try {
      const body = { status: newStatus };
      const response = await fetch(`http://localhost:5000/orders/${order.order_id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json', token: localStorage.token },
        body: JSON.stringify(body),
      });
      if (response.ok) {
        setProgress(progression[newStatus]);
        setInternalStatus(newStatus);
      }
    } catch (err) {
      console.error(err.message);
    }
  };
  
  useEffect(() => {
    setProgress(progression[status]);
  }, []);

  return (
    <>
      <div className="progress">
        <div
          className="progress-bar progress-bar-striped progress-bar-animated"
          role="progressbar"
          style={{ width: `${progress}%` }}
        >
          {' '}
        </div>
      </div>
      <p className="text-center my-1">{internalStatus}</p>
    </>
  );
};

const STAGES = {
  PENDING: 'Pending Order Confirmation',
  CONFIRMED: 'Order Confirmed',
  PICKING_UP: 'Picking Up',
  EXAMINING: 'Examining',
  SANITIZING: 'Sanitizing',
  RECYCLING: 'Recycling',
};

const progression = {
  [STAGES.PENDING]: 5,
  [STAGES.CONFIRMED]: 20,
  [STAGES.PICKING_UP]: 40,
  [STAGES.EXAMINING]: 60,
  [STAGES.SANITIZING]: 70,
  [STAGES.RECYCLING]: 100,
};

CodePudding user response:

You can pass different arguments to your function as a third argument of setTimeout.

setTimeout(updateStatus, 1000, ...args)

(using your internalStatus as status in my example)

Also, since status is in your state, you can handle a next setTimeout on a useEffect() hook depending on your logic.

useEffect(() => {

   if status something
   otherStatus = somethingElse
   updateOtherStatusAfter = ...

   setTimeout(updateStatus, updateOtherStatusAfter, otherStatus)

}, [ status ] )

Observe that status is in the dependency list of useEffect.

This means that every time the status changes, the function that you pass inside the useEffect will be triggered.

After a comment of Drew Reese about clean up, consider something like this.

useEffect(() => {

  const tId = setTimeout(...)

  return () => {
     clearTimeout(tId)
  }

}, [ ... ] )

CodePudding user response:

If I understand correctly your problem, you want to call periodically updateStatus AND ensure that the order of updateStatus call is respected.

For this I see two solutions :

In any case, you will need to clean these when component unmounts

  • Related