Armando Guarino
Armando Guarino

Reputation: 1621

How to fetch data and then perform other tasks asynchronously on load with useEffect (React JS)

I'm struggling to figure out how to perform this:

const [stateOne, setStateOne] = useState();
const [stateTwo, setStateTwo] = useState();

useEffect(() => {
  /* fetch data */

  setStateOne(); /* not before data is fetched */
  setStateTwo(); /* not before data is fetched and setStateOne is complete */
},[])

Is this conceptually right and it is possible to run such tasks asynchronously within useEffect?

Upvotes: 0

Views: 261

Answers (4)

syarul
syarul

Reputation: 2189

This would give you an idea of how to use useEffect

const {useState, useEffect} = React;

const App = () => {
    const [stateOne, setStateOne] = useState(null)
    const [stateTwo, setStateTwo] = useState(null)

    useEffect(() => {
       stateOne && call(setStateTwo); 
    },[stateOne])
    
    const call = setState => {
      let called = new Promise(resolve => {
        setTimeout(() => {
          resolve(true)
        }, 2000)
      })
      called.then(res => setState(res))
    }
    
    return (
      <div>
        <button onClick={() => call(setStateOne)}>make call</button>
        <pre>stateOne: {JSON.stringify(stateOne)}</pre>
        <pre>stateTwo: {JSON.stringify(stateTwo)}</pre>
      </div>
    )  
}

ReactDOM.render(
  <App />,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Upvotes: 0

Ashok
Ashok

Reputation: 2932

use async/await with the direct arrow function

useEffect(() => {
  (async() => {
    /* fetch data */
   // await is holding process till you data is fetched
   const data = await fetchData()
   // then set data on state one
   await setStateOne(); 
   // then set data on state second
   setStateTwo(); 
  })();
},[])

Upvotes: -1

Shmili Breuer
Shmili Breuer

Reputation: 4147

You can't run async actions in a react hook, so you need to extract your functionality outside the hook and then call it inside the hook, then create a second effect to run after stateOne is updated to update state 2.

const fetchAction = async () => {
    await fetchData(...)/* fetch data */

    setStateOne(); /* not before data is fetched */
    


}

useEffect(() => {
   
},[])

useEffect(() => {
   setStateTwo(); 
},[StateOne])

Upvotes: 1

Adam Jenkins
Adam Jenkins

Reputation: 55613

Multiple effects:

const [asyncA,setAsyncA] = useState();
const [asyncB,setAsyncB] = useState();


useEffect(() => {

  (async() => {
     setAsyncA(await apiCall());
  })();

 // on mount fetch your data - no dependencies
},[]);


useEffect(() => {
  if(!asyncA) return;
  
  (async() => {
     setAsyncB(await apiCall(asyncA));
  })();

  // when asyncA is ready, then get asyncB
},[asyncA]);

useEffect(() => {
  if(!asyncA || !asyncB) return;
  // both are ready, do something
},[asyncA,asyncB])


OR, just an async function in one effect:

useEffect(() => {

  (async() => {
     const first = await apiCallA();
     const second = await apiCallB(first);
  })();

},[]);

Upvotes: 1

Related Questions