The React component fails to load due to the discrepancies in the data retrieved from various asynchronous requests

Creating a travel-related form using React with TypeScript. The initial component

TravelForm

utilizes multiple async-await requests within useEffect hook to update the state of the subsequent component

TravelGuideFields

However, the values of props are not being displayed in my TravelGuideFields component. Upon inspection with React dev tool, the state is correctly updated with new values, but it seems like the component is loading with old values. This could be due to the multiple async-await calls causing the component to render before obtaining the final result value. Is there an alternative way to ensure my components display the updated values?

Here is the first component where the multiple network calls are made within the effect hook:

import { FC, useEffect, useState } from "react";
import {
    getOrderedbooks,
    getOrderedSportsGears,
    getOrderedTravelMaps
} from "../../httpRequests/TravelRequests";

import TravelGuideFields from "./TravelGuideFields";

const TravelForm: FC = () => {
    // states
    const [inputs, setInputs] = useState<TravelInputInterface>({
        bookName: "",
        bookPrice: 0.0,
        runningShoeBrand: "",
        runningShoeCost: 0.0,
        mapType: "",
        mapCost: 0.0,
    });

    useEffect(() => {
        const resultInputs: TravelInputInterface = {
             bookName: "",
             bookPrice: 0.0,
             runningShoeBrand: "",
             runningShoeCost: 0.0,
             mapType: "",
             mapCost: 0.0,
        };
        const fetchBooks = async () => {
            const res = await getOrderedbooks();
        

            if (res !== undefined) {
                resultInputs.bookName = res.BOOK_NAME;
                resultInputs.bookPrice = res.BOOK_PRICE;
          
            }
        };
        fetchBooks();

        const fetchSportsGear = async () => {
            const res = await getOrderedSportsGears();
        

            if (res !== undefined) {
                resultInputs.runningShoeBrand = res.SHOE_BRAND;
                resultInputs.bookPrice = res.SHOE_PRICE;
          
            }
        };
        fetchSportsGear();

        const fetchTravelMaps = async () => {
            const res = await getOrderedTravelMaps();
            
            if (res !== undefined) {
                resultInputs.mapType = res.MAP_TYPE;
                resultInputs.mapCost = res.MAP_COST;
       
            }
        };

        fetchTravelMaps();
        console.log({ resultInputs });
        setInputs(resultInputs);
    }, []);

    
    return <TravelGuideFormFields inputs={inputs} />;
};
default BlockchainConstantsForm;

//TravelGuideFields component

const TravelGuideFields: FC<any> = ({inputs}) => {

return (
<div>
<div class="books"><input value={inputs.bookName} disabled/>
<input value={inputs.bookPrice} disabled/></div>
<div class="maps"><input value={inputs.mapType} disabled/></div>
<div class="sports"><input value={inputs.runningShoe} disabled/></div>
</div>
)
}

export default TravelGuideFields

//TravelRequests (HTTP request generator file)

//Books
export const getOrderedbooks = async (): Promise<bookInterface | undefined> => {
    const res = await get(
         `${mainURL}/books`
     );
    
    if (res.status === 200) {
        
        return res.data;
    }

    return undefined;
};

//SportsGear

export const getOrderedSportsGears = async (): Promise<sportsInterface | undefined> => {
        const res = await get(
             `${mainURL}/sports`
         );
        
        if (res.status === 200) {
            
            return res.data;
        }
    
        return undefined;
    };

//Travelmaps

    export const getOrderedTravelMaps = async (): Promise<mapInterface | undefined> => {
            const res = await get(
                 `${mainURL}/map`
             );
            
            if (res.status === 200) {
                
                return res.data;
            }
        
            return undefined;
        };

Answer №1

Here is where the issue lies.

The code lacks consistency in using async-await throughout.

    useEffect(() => {
        const resultInputs: TravelInputInterface = {
             bookName: "",
             bookPrice: 0.0,
             runningShoeBrand: "",
             runningShoeCost: 0.0,
             mapType: "",
             mapCost: 0.0,
        };
        const fetchBooks = async () => {
            const res = await getOrderedbooks();
        

            if (res !== undefined) {
                resultInputs.bookName = res.BOOK_NAME;
                resultInputs.bookPrice = res.BOOK_PRICE;
          
            }
        };
        fetchBooks();

        const fetchSportsGear = async () => {
            const res = await getOrderedSportsGears();
        

            if (res !== undefined) {
                resultInputs.runningShoeBrand = res.SHOE_BRAND;
                resultInputs.bookPrice = res.SHOE_PRICE;
          
            }
        };
        fetchSportsGear();

        const fetchTravelMaps = async () => {
            const res = await getOrderedTravelMaps();
            
            if (res !== undefined) {
                resultInputs.mapType = res.MAP_TYPE;
                resultInputs.mapCost = res.MAP_COST;
       
            }
        };

        fetchTravelMaps();
        console.log({ resultInputs });
        setInputs(resultInputs);
    }, []);

The above code snippet indicates the problem area.

To resolve this, you can modify the code as follows:

    useEffect(() => {
        const promises = [getOrderedbooks, getOrderedSportsGears, getOrderedTravelMaps];

        Promise.all(promises).then(promises => {
            const [booksResponse, sportsGearResponse, travelMapsResponse] = promises;

            const resultInputs: TravelInputInterface = {
                bookName: "",
                bookPrice: 0.0,
                runningShoeBrand: "",
                runningShoeCost: 0.0,
                mapType: "",
                mapCost: 0.0,
           };

            if (booksResponse !== undefined){
                resultInputs.bookName = booksResponse.BOOK_NAME;
                resultInputs.bookPrice = booksResponse.BOOK_PRICE;
            }

            if (sportsGearResponse !== undefined){
                resultInputs.runningShoeBrand = sportsGearResponse.SHOE_BRAND;
                resultInputs.bookPrice = sportsGearResponse.SHOE_PRICE;
            }

            if (travelMapsResponse !== undefined) {
                resultInputs.mapType = travelMapsResponse.MAP_TYPE;
                resultInputs.mapCost = travelMapsResponse.MAP_COST;
            }

            setInputs(resultInputs);
        })        
    }, []);

Using Promise.all guarantees that the logic runs after all API calls are completed. As useEffect cannot be an async function, using .then provides a cleaner alternative to utilizing async-await.

If desired, you can still employ async-await by encapsulating the entire useEffect within another async function and invoking it inside the useEffect.

Answer №2

Have you considered using promise.all() with await? Missing the await keyword can result in a promise being returned instead of the desired data. Give this code snippet a try and inform me of whether or not it resolves your issue:

const [booksResponse, sportsGearResponse , travelMapsResponse] = await 
Promise.all([
getOrderedbooks(),
getOrderedSportsGears(),
getOrderedTravelMaps(),
]);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The method of evaluating in-line is distinct from evaluating outside of the

What causes the compiler to produce different results for these two mapped types? type NonNullableObj1<O> = {[Key in keyof O] : O[Key] extends null ? never : O[Key]} type NotNull<T> = T extends null ? never : T; type NonNullableObj2<T> = ...

Implementing promises when updating data in Firestore with JavaScript on Firebase

I'm looking to redirect the user to another page once their name has been updated. The challenge I'm facing is knowing when to use my location.replace function and how to incorporate promises in this situation. (username.value represents the new ...

Strange occurrences with HTML image tags

I am facing an issue with my React project where I am using icons inside img tags. The icons appear too big, so I tried adjusting their width, but this is affecting the width of other elements as well. Here are some screenshots to illustrate: The icon wit ...

Angular is encountering a circular dependency while trying to access a property called 'lineno' that does not actually exist within the module exports

I am working on an Angular project and using the Vex template. My project utilizes Angular 9 and Node.js v15.2.0. Every time I run the project with the command ng serve -o, it displays a warning message. https://i.stack.imgur.com/8O9c1.png What could b ...

How should we provide the search query and options when using fuse.js in an Angular application?

Having previously utilized fuse.js in a JavaScript project, I am now navigating the world of Angular. Despite installing the necessary module for fuse.js, I'm encountering difficulties implementing its search functionality within an Angular environmen ...

The definition of "regeneratorRuntime" is missing in the rete.js library

After encountering a problem, I managed to find a potential solution. My current challenge involves trying to implement Rete.js in Next.js while using Typescript. The specific error message that's appearing is: regeneratorRuntime is not defined Be ...

Issue with dynamic HTML preventing Bootstrap tooltip functionality

There's an HTML page where a section is dynamically generated through HTML injection from a typescript angularjs controller using $sce and ng-bind-html. The issue is that the custom bootstrap tooltip style doesn't seem to be applied, and only t ...

Attempting to invoke a function containing a promise in Javascript

Calling the function numberOfRedeems(dealId) from another function named setUpData raises an issue where the numberOfRedeems() function, which includes a promise and returns "counter", always returns as undefined when executed within the setUpData function ...

Alerting Users Before Navigating Away from an Angular Page

I am looking to implement a feature in my app that will display a warning message when attempting to close the tab, exit the page, or reload it. However, I am facing an issue where the warning message is displayed but the page still exits before I can resp ...

The absence of the 'profileStore' property is noticed in the '{}' type, which is necessary in the 'Readonly<AppProps>' type according to TypeScript error code ts(2741)

I'm currently using MobX React with TypeScript Why am I getting an error with <MainNote/>? Do I just need to set default props? https://i.stack.imgur.com/5L5bq.png The error message states: Property 'profileStore' is missing in typ ...

What steps should I take to address this issue using IONIC and TypeScript?

Running into an issue with my TypeScript code for an Ionic project. I'm attempting to pass the value of the variable (this.currentroom) from the getCurrentRoom() function to another function (getUser()) but it's not working. Here's my chat s ...

The variable 'selectedvalue' is being accessed before it has been initialized

I'm currently working on sharing the date between components using BehaviorSubject, but I'm encountering an error in the process. public data = new BehaviorSubject<any>(this.selectedValue); public sharedData = this.data.asObservable(); sele ...

Angular 7 ERROR: The SystemJS reference is missing

In the process of developing an Angular 7 project with systemjs for dynamic module loading, I encountered an issue. Upon attempting to utilize it, I encountered the following error: ERROR ReferenceError: SystemJS is not defined Within my package.json f ...

"Unexpected Type Inference Issue: A variable initially defined as a string inexplicably transforms into 'undefined'

Currently, I am incorporating the await-to-js library for handling errors (specifically utilizing the to method from the library). In an intriguing scenario, the variable type shifts to string | undefined within a for..of loop, whereas outside of the loop ...

Confirm the presence of a particular sub collection within Firebase/Firestore by returning true

Can you confirm if the sub-collection named 'categories' exists within the users collection in Firestore? Please return true if it exists and false if it does not. ...

Navigating through a React application with several workspaces - the ultimate guide

Currently, I am working on implementing a monorepo setup inspired by this reference: https://github.com/GeekyAnts/nativebase-templates/tree/master/solito-universal-app-template-nativebase-typescript In this repository, there are 4 distinct locations wher ...

How to access enums dynamically using key in TypeScript

export enum MyEnum{ Option1, Option2, Option3 } string selection = 'Option1'; MyEnum[selection] results in an error: The type string cannot be assigned to the type MyEnum On the other hand: MyEnum['Option1'] works as ...

What is the best way to retrieve data in my client component without risking exposing my API key to unauthorized users?

To retrieve information, I plan to use pagination in order to specify a particular page number within the API URL and fetch additional data by updating the value of page. The process of fetching data in my server component is as follows: // fetchData.tsx ...

angular displaying incorrect values for counter

Hi there, I am new to using Angular and I'm currently facing an issue with increasing and decreasing product quantity on the cart page. The problem is that in my first index it works fine, but in the second index, the value starts with the first index ...

Leveraging a component as a property of an object in Vue version 3

I'm trying to figure out if there's a way to use a Component as a property in Vue 3. Consider the TypeScript interface example below: import type { Component } from 'vue' interface Route { url: string icon: Component name: ...