-4

I'm using useEffect and filling my state on the first render

 const [data, setData ] = useState({});
const [isLoading, setIsLoading] = useState(false);


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

 const fetchData = async () => {
        setIsLoading(true)
        await sanityAPI.fetch(
            `url/ToGetData`
          ).then((res) => {
            setData(res)
            setIsLoading(false)
          }).catch((err) => {
              console.log(err)
          });
 }

when page is rendered the first time, if I console.log(data,'first time') in useEffect data, it gives me null

but after the first time if I go and just add another string in console.log(data,'second time'), and save it, the data shows, on the console.log.

Thanks a lot.

  • 1
    Why are you using both await and then ? – Kunal Mukherjee Sep 08 '21 at 08:52
  • `data` will be empty object (`{}`) on the initial render, and then eventually updated by the `fetch`. `useEffect` runs *after* a render. This is normal. Is there an issue? React state updates are also asynchronously processed, so if you are trying to log the state right after enqueueing an update it will be the state value from the *current* render cycle. – Drew Reese Sep 08 '21 at 08:53
  • useEffect runs *after* the first render. You can pass a callback to `useState` to [lazy load your initial state](https://stackoverflow.com/questions/58539813/lazy-initial-state-what-is-and-where-to-use-it) if need be, but otherwise just account for initial empty state followed by update after the useEffect runs. – pilchard Sep 08 '21 at 08:53
  • Is there another workaround, that I can do this, because I need the data that I'm getting, to call other functions that will check for other things. – Endrit Shabani Sep 08 '21 at 08:56
  • Can you update your question to include your actual relevant code? – Drew Reese Sep 08 '21 at 08:57
  • Why don't you just use another useEffect call to execute those other functions you are talking about after the data is loaded? – Dan Zuzevich Sep 08 '21 at 09:03
  • @DRewReese I need to manipulate the data, validate if a condition renders then display data if that conditions is true. The point is that on the first render isn't filling data in useState. – Endrit Shabani Sep 08 '21 at 09:08
  • @DanZuzevich I don't know, if you can call two times useEffect. Can you explain that to me – Endrit Shabani Sep 08 '21 at 09:08
  • Well, you can't do any of that until you've fetched the data, which as we pointed out, is pretty normal in React, and your code should handle missing/empty data for the initial and first few renders until state is set and ready. You can use as many React hooks as the component needs. – Drew Reese Sep 08 '21 at 09:16

1 Answers1

-1

There is really no way around what you are talking about. You need to wait until your data has been fetched, then you can execute those functions that depend on that data. You can add an additional useEffect to handle what to do after the data has been fetched and set to state.

Personally, sometimes I find it easier to set the data to null initially, rather than an empty object. This makes it easy to check in useEffect, JSX code etc if your data is available. Otherwise you'd have to do something like Object.keys(data).length > 0 each time to see if you can use your data.

I've also rewrote some of your code, because you probably shouldn't be mixing await with then.

const [data, setData ] = useState(null);
const [isLoading, setIsLoading] = useState(false);


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

 useEffect(() => {
   if(data) {
     // do stuff here
   }
   
 }, [data])

 const fetchData = async () => {
    try {
      setIsLoading(true)
      const res = await sanityAPI.fetch(`url/ToGetData`)
      setData(res)
    } catch(error) {
      console.log(error) 
    } finally {
      setIsLoading(false)
    } 
 }

return (
  <div>
   ...bunch of code

   {
     data && <div>{data.foo}</div>
   }
  </div>
)
Dan Zuzevich
  • 3,651
  • 3
  • 26
  • 39