React use useEffect to load data asynchronously

React use useEffect to load data asynchronously

  

I have a parent component that has a child component inside it which loaded data asynchronously currently I have:

<Parent> 
  <AsyncChild data={props.data} />
  <Child />
</Parent>

Inside my AsyncChild component I have:

const processDataAsynchronously = data => {
      // do stuff with a huge chunk of data
} 

export default function AsyncChild(props) {

    const data = props.data;
    const [dataLoaded, setDataLoaded] = useState(false);
    const [myData, setMyData] = useState({});

    useEffect(() => {
        let mounted = true;
        processDataAsynchronously(data);
        .then(data => {
            if(mounted) {
                setMyData(data);
                setDataLoaded(true);
            }
        });  
        return () => {
            mounted = false;
        }   
       }, [data])

    const getComponentData = () => {
        if(dataLoaded && !myData){ 
            // if data has loaded and is empty return empty
            return <span />
        } else if (!myData && !dataLoaded)  { 
            // if data is empty and loading is not complete - return loading component
            return <Loader />;
        } else {
            return (
                // return style data
            )
        }      
    }

    return (
        <div>
            {getComponentData()}
        </div>  
    )
} 

What I want to do is to load <Child /> and while <AsyncChild /> is processing it's data asynchronously, display a loader above the <Child /> component. However, currently the loader does not display and both of the child components are displayed together. How can I do this correctly?

Answer

You can add a state into parent component like this:

import { useState } from 'react';


export default function App () {
 
 [isLoading, setLoading] = useState(false);

 return (
  <Parent> 
   <AsyncChild data={props.data} setLoading={setLoading}/>
   {isLoading && <Loader />}
   <Child />
  </Parent>
 )
}

Then in AsyncChild you can set the isLoading in the useEffect:

useEffect(() => {
    setLoading(true); // <----- START LOADING
    let mounted = true;
    processDataAsynchronously(data);
    .then(data => {
        if(mounted) {
            setMyData(data);
            setDataLoaded(true);
        }
        setLoading(false); // <----- END LOADING
    });  
    return () => {
        mounted = false;
    }   
   }, [data])
© 2024 Dagalaxy. All rights reserved.