React: Exploit useEffect hook to create an asynchronous while loop

React: Exploit useEffect hook to create an asynchronous while loop

This article shows you how to exploit the useEffect hook in React to create a while loop for calling an asynchronous function.

The problem

While developing a order management system for one of our projects, I stumbled over a problem using Next.js Serverless Functions. The problem I had was, that there is a pre configured limit with using Serverless Functions, which leads to a request or response with a maximum size of 5MB. The database I worked with returned documents way larger than 5MB, so I needed to implement a pagination for the database requests. When using pagination, you can only get a fracture of the data you actually need. So if you need to fill a table with the data of the whole database, it would be really nice to call the database with pagination until you don't receive any more data. In my case, I needed to call a MongoDB (using Mongoose) on page load to fill an order table with all available orders in the database. To achieve that with pagination, I needed to find a way to call my fetchOrders-function in an asynchronous "while loop".

Prerequisites

In this example, I'm just using the useState and useEffect hooks from React.

Doing the loop

To solve my problem, I searched the internet for a solution for my loop problem. After a while without finding anything useful, I thought of exploiting the useEffect hook of React, which will be called on any change of states in the useEffect's dependency array. To be sure, that the useEffect hook is called as long as I need it to be called, I implemented a state, which acts like a mutex. I just change the boolean state to the opposite state (if it's true, it will be changed to false, and vice versa) on each fetchOrders()-function call, so the useEffect hook will be called on the next render cycle.

My approach for a solution

In the following, you are going to see a template example for exploiting the useEffect hook to call a function over and over again until a specific state is reached (in this example: noMoreData === true).

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

const FetchDataLoop = () => {
  const [dataArray, setDataArray] = useState([]);
  const [noMoreData, setNoMoreData] = useState(false);
  const [loopMutex, setLoopMutex] = useState(true);

  const fetchData = async () => {
    try {
      const { status, data } = await axios.get("/your/api/route");
      if (status === 200) {
        if (data["fetchedDataArray"].length > 0) {
          const extendedDataArray = dataArray.concat(data["fetchedDataArray"]);
          setDataArray(extendedDataArray);
        }
      }
    } catch (error) {
      // 404 is usually the status, when there is no more data to fetch
      if (error.response.status === 404) {
        setNoMoreData(true);
      } else {
        console.error(error);
      }
      setLoopMutex(!loopMutex);
    }
    setLoopMutex(!loopMutex);
  };

  useEffect(() => {
    if (!noMoreData) {
      fetchData();
    }
  }, [loopMutex]);

  return <></>;
};

export default FetchDataLoop;

Be sure to use this example as a template or for your own solution finding.

Entdecken Sie die Vorteile­ unserer Individual­entwicklung

In einem kostenlosen Erstgespräch vor Ort - wahlweise auch am Telefon oder über Microsoft Teams - lernen wir uns unverbindlich kennen und erarbeiten gemeinsam mit Ihnen ein Lösungskonzept für Ihre Ziele. Wir freuen uns auf Sie!