I've been through several variations of fetching with useEffect, and I finally settled in on something without dependency arrays. The previous version lacked clarity when trying to fetch two or three things in a specific order, and performing state checks in the effect(s), e.g., if (!states), if (states && !zips) or something. Please excuse all of my contrived examples:
exportconstRandomDog=()=>{const[src,setSrc]=useState()const[status,setStatus]=useState('idle')useEffect(()=>{constfetchRandomDog=async()=>{setStatus('loading')try{letres=awaitfetch("https://dog.ceo/api/breeds/image/random")setSrc(awaitres.json().message)setStatus('success')}catch(error){setError(error)setStatus('failed')}}if(status==='idle'){fetchRandomDog()}})return<imgsrc={src}alt='A random dog'/>}
Of course, there are already three pieces of state moving in the same direction, and even with an object things will get pretty unruly, so it made sense to throw the state into a context to handle all the different endpoints:
exportconstRandomDog=()=>{conststate=useAppState()constdispatch=useAppDispatch()const{error,src,status}=stateuseEffect(()=>{constfetchRandomDog=async()=>{dispatch({type:'RandomDogRequested'})try{letres=awaitfetch("https://dog.ceo/api/breeds/image/random")letdata=awaitres.json().messagedispatch({type:'RandomDogReceived',payload:data})}catch(error){dispatch({type:'RandomDogRequestFailed',payload:error})}}if(status==='idle'){fetchRandomDog()}})return<imgsrc={src}alt='A random dog'/>}
This worked fine, too. Even if I included dispatch and status in the dependency array, it was no problem. Unfortunately, there's no cleanup, and that should not go missing:
exportconstRandomDog=()=>{conststate=useAppState()constdispatch=useAppDispatch()const{error,src,status}=stateuseEffect(()=>{constabortController=newAbortController()constfetchRandomDog=async()=>{dispatch({type:'RandomDogRequested'})try{letres=awaitfetch("https://dog.ceo/api/breeds/image/random",{signal:abortController.signal})letdata=awaitres.json().messagedispatch({type:'RandomDogReceived',payload:data})}catch(error){dispatch({type:'RandomDogRequestFailed',payload:error})}}if(status==='idle'){fetchRandomDog()}return()=>{abortController.abort()}})return<imgsrc={src}alt='A random dog'/>}
Suddenly, I have an issue where as soon as the status is changed to loading, the fetch is cancelled. I added a check for the additional status, status === 'idle' || status === 'loading', and while my dog arrived unharmed, it wasn't without a cancelled request happening first. I need to get back to the code sandbox I was tinkering with when I was learning this bit.
The other time I run into issues with useEffect is when I am watching a dependency for a change, and the subsequent update causes a change to the dependency. I've stopped a runaway like this before by freezing the initial dependency with useRef, something along the lines of:
constinitialAccounts=React.useRef(accounts)useEffect(()=>{if(someCondition){updateAccounts([...initialAccounts.current,someProp:updatedValue])}},[updateAccounts])// neither accounts nor initialAccounts is required here now
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
I've been through several variations of fetching with useEffect, and I finally settled in on something without dependency arrays. The previous version lacked clarity when trying to fetch two or three things in a specific order, and performing state checks in the effect(s), e.g.,
if (!states), if (states && !zips)
or something. Please excuse all of my contrived examples:Of course, there are already three pieces of state moving in the same direction, and even with an object things will get pretty unruly, so it made sense to throw the state into a context to handle all the different endpoints:
This worked fine, too. Even if I included dispatch and status in the dependency array, it was no problem. Unfortunately, there's no cleanup, and that should not go missing:
Suddenly, I have an issue where as soon as the status is changed to loading, the fetch is cancelled. I added a check for the additional status,
status === 'idle' || status === 'loading'
, and while my dog arrived unharmed, it wasn't without a cancelled request happening first. I need to get back to the code sandbox I was tinkering with when I was learning this bit.The other time I run into issues with useEffect is when I am watching a dependency for a change, and the subsequent update causes a change to the dependency. I've stopped a runaway like this before by freezing the initial dependency with useRef, something along the lines of: