Home > Software design >  How can I ensure that a React component is loaded only after some API call has been made?
How can I ensure that a React component is loaded only after some API call has been made?

Time:04-07

I have a App component as below and it has MyHeaderComponent as it's child.

On MyHeaderComponent load, I invoke a service call/endpoint. However, I want to ensure that MyHeaderComponent itself is invoked only after callSomeServiceEndpoint has finished. Not sure if that is possible, since the call to /myrefresh is an opaque response (just returning me a cookie)

function App() {
    const [url, setUrl] = useState({});
    const urls = useMyFetch('api/myApiURLs', {});
    const [isEntitled, setIsEntitled] = useState(false);

    useEffect(() => {
        if (Object.keys(urls).length > 0) {
            setUrl(urls);
            callSomeServiceEndpoint(urls);
        }
    }, [urls])

    return (
        <>
            <MyContextProvider>
                <MyHeaderComponent url={urls} />                
            </MyContextProvider>
        </>
    );
}

export default App;

Below is callSomeServiceEndpoint

export default function callSomeServiceEndpoint(myURLs) {
    const int = 1 * 60 * 1000;
    function myrefresh(myURLs) {
        Object.values(myURLs).forEach((myURL) => {
            fetch(`${myURL}/myapi/myrefresh`, {
                mode: 'no-cors',
                credentials: 'include'
            });
        });
    }
    myrefresh(myURLs);
    const refInterval = setInterval(myrefresh, int, myURLs);
    window.addEventListener("beforeunload", function () {clearInterval(refInterval)});
}

Below is useMyFetch

import {useEffect, useState} from 'react';

export default function useMyFetch(url, data) {
    const [url] = useState(url);
    const [mydata, setMyData] = useState(data);
    useEffect(() => {
        fetch(url, {mode: 'no-cors', credentials: 'same-origin'})
            .then(response => {
                // Response handling and setMyData()
            })
            .catch(error => {                
            });
    }, [url]);

    return data;
}

CodePudding user response:

What do you think about a boolean in custom hook triggered in in fetch's then? Something like:

import {useEffect, useState} from 'react';

export default function useMyFetch(url, data) {
    const [url] = useState(url);
    const [mydata, setMyData] = useState(data);
    const [isDone, setIsDone] = useState(false); //<-- boolean here
    useEffect(() => {
        fetch(url, {mode: 'no-cors', credentials: 'same-origin'})
            .then(response => {
                // Response handling and setMyData()

                setIsDone(true); //<-- set to true
            })
            .catch(error => {                
            });
    }, [url]);

    return {mydata, isDone};
}

And the App component:

function App() {
    const [url, setUrl] = useState({});
    const [urls, isDone] = useMyFetch('api/myApiURLs', {});
    const [isEntitled, setIsEntitled] = useState(false);

    useEffect(() => {
        if (Object.keys(urls).length > 0) {
            setUrl(urls);
            callSomeServiceEndpoint(urls);
        }
    }, [urls])

    return (
        <>
            <MyContextProvider>
                {isDone && <MyHeaderComponent url={urls} />}  //<-- conditional rendering             
            </MyContextProvider>
        </>
    );
}

export default App;

CodePudding user response:

You may create a state like const [endpointCalled, setEndpointCalled] = useState(false); in the App component.

Then change callSomeServiceEndpoint so that it returns a promise in order to rewrite it like

callSomeServiceEndpoint(urls).then(setEndpointCalled(true));

and finally

<>
 <MyContextProvider>
  {endpointCalled ? <MyHeaderComponent url={urls} /> : null}                
 </MyContextProvider>
</>
  • Related