Coding hobbyist, recently went through a react basics course and now studying apis. In trying to work with both I've ran into a situation where the video course instructor says fetching the api would be best to be done in the useEffect since it's reaching outside the app and could have side effects. In trying to make these calls I have one api that could get away without a clean up return function - though I'd like to write one if that is best practice the second api certainly needs a clean up but I can't map over an array of objects to fetch from a key/property in each object. What returns as data looks like an object but what sets to state is an array of promises (do not have much experience with new Promise or async/await to write these correctly to get the data returned correctly, if this is part of the solution.
Things I'm especially confused about
- First, the first useEffect clean up function was suppose to set the count state to 1, but when the component mounts, dismounts, and mounts again it still seems to enter the if block
- Second, the second useEffect if you console log the fetch at the .then block with data you get the data object but finalCoinArr is just an array of Promises
- Third, is the second useEffect clean up function going to set the gecko.data state back to an empty array? if so is there a way not to empty that array but after the first api call saving the data there tell it not to make another api call.
Here are a couple of the resources I've read
https://www.freecodecamp.org/news/async-await-javascript-tutorial/
https://beta.reactjs.org/learn/synchronizing-with-effects
Why useEffect running twice and how to handle it well in React?
function App() {
const [unsplash, setUnsplash] = React.useState({data:{urls:{full:'', regular:''},user:{name:'',portfolio_url:''}}})
const [gecko, setGecko] = React.useState({data:[]})
const [count, setCount] = React.useState(0);
const scrimbaUrl = `https://apis.scrimba.com/unsplash/photos/random?orientation=landscape&query=nature`
const coinGeckoUrl = `https://api.coingecko.com/api/v3/coins/`
const coinArr = [{name:'bitcoin', image:{small:'https://assets.coingecko.com/coins/images/1/small/bitcoin.png?1547033579'}},{name:'dogecoin', image:{small:"https://assets.coingecko.com/coins/images/5/small/dogecoin.png?1547792256"}},{name:'ethereum', image:{small:"https://assets.coingecko.com/coins/images/279/small/ethereum.png?1595348880"}}, {name:'litecoin', image:{small:"https://assets.coingecko.com/coins/images/2/small/litecoin.png?1547033580"}}]
React.useEffect(()=>{
if(count === 0){
fetch(scrimbaUrl)
.then(res=>res.json())
.then(data=>{
// console.log('called fetch')
setUnsplash((prevState)=>{
return {...prevState, data:data}
})
})
.catch((err)=>{
console.log(`ScrimbaE:${err}`)
let defaultBackground = 'https://images.unsplash.com/photo-1503264116251-35a269479413?crop=entropy&cs=tinysrgb&fm=jpg&ixid=MnwxNDI0NzB8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NzExNTg5MTE&ixlib=rb-4.0.3&q=80'
let defaultName = 'Aperture Vintage'
let defaultPortfolio = 'https://creativemarket.com/PedroCS?u=PedroCS'
let defaultUnsplash = {urls:{full:defaultBackground}, user:{name:defaultName, portfolio_url:defaultPortfolio}}
setUnsplash((prevState)=>{
return {...prevState, data:defaultUnsplash}
})
})
}
return ()=>{
setCount((prevCount)=>prevCount+1)
}
},[])
React.useEffect(()=>{
if(count === 0){
let finalCoinArr = coinArr.map((ele)=>{
return fetch(`${coinGeckoUrl}${ele.name}`)
.then(res=>res.json())
.then(data=>{
return data
})
})
setGecko(()=>{
return {data:finalCoinArr}
})
console.log(finalCoinArr)
}
return ()=>{
setGecko(()=>{
return {data:[]}
})
}
},[])
// console.log(gecko)
/*Returned */
// {data: Array(4)}
// data: Array(4)
// 0: Promise {<fulfilled>: {…}}
// 1: Promise {<fulfilled>: {…}}
// 2: Promise {<fulfilled>: {…}}
// 3: Promise {<fulfilled>: {…}}
// length: 4