1

I'm pulling data from a Realm file db, but data seem to only appear on 2nd render. Here's my code:

import React, { useState, useEffect } from 'react'
import {getAllArchive} from '../Schemas/activitiesArchiveSchema';

const Stats = () => {
  const [Archives, setArchives] = useState();

  useEffect(() => {
    (async () => setArchives(await getAllArchive()))();
    console.log(JSON.stringify(Archives))
  }, []);

DB function:

export const getAllArchive = () => {
    return new Promise((resolve, reject) => {
        Realm.open(databaseOptions).then(realm => {
            let activitiesList = realm.objects(ARCHIVE_LIST_SCHEMA)
            resolve(activitiesList)
        }).catch((error) => reject(error))
    })
}

Output:

 LOG  undefined
 LOG  {"0":{"title":"sw2","records":{"0":{"date":"4/28/2021","seconds":7,"minutes":0,"hours":1},"1":{"date":"4/27/2021","seconds":7,"minutes":0,"hours":0},"2":{"date":"4/28/2021","seconds":7,"minutes":0,"hours":0}}},"1":{"title":"jj","records":{"0":{"date":"4/25/2021","seconds":0,"minutes":55,"hours":1}}},"2":{"title":"l,kl","records":{"0":{"date":"4/28/2021","seconds":4,"minutes":12,"hours":1}}},"3":{"title":"fsdfdsf","records":{"0":{"date":"4/25/2021","seconds":4,"minutes":43,"hours":1}}},"4":{"title":"sideProj","records":{"0":{"date":"4/26/2021","seconds":30,"minutes":29,"hours":1},"1":{"date":"4/27/2021","seconds":15,"minutes":18,"hours":1}}},"5":{"title":"work","records":{"0":{"date":"4/28/2021","seconds":36,"minutes":13,"hours":0},"1":{"date":"4/28/2021","seconds":37,"minutes":11,"hours":3}}},"6":{"title":"plp","records":{"0":{"date":"4/25/2021","seconds":2,"minutes":12,"hours":3}}},"7":{"title":"fff","records":{"0":{"date":"4/25/2021","seconds":3,"minutes":10,"hours":2}}},"8":{"title":"Work","records":{"0":{"date":"4/27/2021","seconds":1,"minutes":0,"hours":0}}},"9":{"title":"chilling","records":{"0":{"date":"4/27/2021","seconds":40,"minutes":4,"hours":3},"1":{"date":"4/27/2021","seconds":0,"minutes":0,"hours":0}}}}

Can someone point out any issues in the code plz? thx

Omar Odaini
  • 101
  • 1
  • 7

4 Answers4

1

This is not a surprise that your data is not loaded in the very first render of the component. First, let's see what useEffect does if you don't provide any dependency- it executes on every re-render.

on this line of code:

(async () => setArchives(await getAllArchive()))();

you're fetching data that is asynchronous, the execution will not pause here. so, console.log(JSON.stringify(Archives)) will be executed. If Archived is still undefined (meaning data fetching is incomplete) you see LOG undefined. When, the asynchronous data fetching is completed and state updated what causes the component rerender hence useEffect is called again and you see

LOG  {"0":{"title":"sw2","records":{"0":{"date":"4/28/2021","seconds":7,"minutes":0,"hours":1},"1":{"date":"4/27/2021","seconds":7,"minutes":0,"hours":0},"2":{"date":"4/28/2021","seconds":7,"minutes":0,"hours":0}}},"1":{"title":"jj","records":{"0":{"date":"4/25/2021","seconds":0,"minutes":55,"hours":1}}},"2":{"title":"l,kl","records":{"0":{"date":"4/28/2021","seconds":4,"minutes":12,"hours":1}}},"3":{"title":"fsdfdsf","records":{"0":{"date":"4/25/2021","seconds":4,"minutes":43,"hours":1}}},"4":{"title":"sideProj","records":{"0":{"date":"4/26/2021","seconds":30,"minutes":29,"hours":1},"1":{"date":"4/27/2021","seconds":15,"minutes":18,"hours":1}}},"5":{"title":"work","records":{"0":{"date":"4/28/2021","seconds":36,"minutes":13,"hours":0},"1":{"date":"4/28/2021","seconds":37,"minutes":11,"hours":3}}},"6":{"title":"plp","records":{"0":{"date":"4/25/2021","seconds":2,"minutes":12,"hours":3}}},"7":{"title":"fff","records":{"0":{"date":"4/25/2021","seconds":3,"minutes":10,"hours":2}}},"8":{"title":"Work","records":{"0":{"date":"4/27/2021","seconds":1,"minutes":0,"hours":0}}},"9":{"title":"chilling","records":{"0":{"date":"4/27/2021","seconds":40,"minutes":4,"hours":3},"1":{"date":"4/27/2021","seconds":0,"minutes":0,"hours":0}}}}
Mateen
  • 1,455
  • 10
  • 17
  • Thats true, I ended up adding a separate useEffect to with that state in dependency array as you see in my comment. thx – Omar Odaini May 02 '21 at 06:29
0

Isn't it just that your console.log is happening before setArchives? Try to force your log to wait for the async return to test it out.

Thiousi
  • 53
  • 1
  • 6
  • I tried (async () => setArchives(await getAllArchive()))().then(()=>console.log(JSON.stringify(Archives)));` if that what you mean, but didn't work. I thought await will wait before running log right? – Omar Odaini Apr 30 '21 at 20:35
  • Have a look at this post: https://stackoverflow.com/questions/53332321/react-hook-warnings-for-async-function-in-useeffect-useeffect-function-must-ret – Thiousi May 01 '21 at 07:50
0

im pretty sure you cannot async setState here:

(async () => setArchives(await getAllArchive()))(); setState is not an async api, is it? try:

useEffect(() => {
  (async () => {
    const data = await getAllArchive();// async fetch data and store it in variable

    console.log(JSON.stringify(data, null, 2)); //log your response

    if(data){

      setArchives(data) //if success, then set state

    }else{
      console.log('could not fetch data') //if fail, resolve error somehow
    }
  }
  )();
  
}, []);
Andris Laduzans
  • 408
  • 4
  • 14
  • Good point! so your code works. However, only when printing `data` var not `Archives` state. How would you get setState to actually update archives. I ran ` console.log(JSON.stringify(Archives)); ` right after the `setArchives (data)` but still undefined. – Omar Odaini Apr 30 '21 at 20:43
  • ofcourse it is undefined, because in the exact moment when the useEffect function is running the state is remaining the same, Here's an analogy: If you ask for a drink at bar, you need to wait for bartender to fix you one, it does not magically appear in front of you while they are making it right? So with the state, your function actually needs to finish running before you can access the updated state. if you actually want to check your state on every update and every render you can place console log right AFTER the useEffect (outside). – Andris Laduzans Apr 30 '21 at 20:51
  • Well, I'm trying to access the state from another `useEffect` or from JSX but still undefined in first render. – Omar Odaini Apr 30 '21 at 21:02
  • because on first render there is nothing... you are waiting for your data to fetch, when it is fetched update state and render. This is why there are loading indicators and splash screens invented. Your question is starting to become about very basic concepts of frontend development i would suggest you to actually read the React documentation. https://reactjs.org/docs/hooks-faq.html#how-can-i-do-data-fetching-with-hooks – Andris Laduzans Apr 30 '21 at 21:06
  • Thanks for your input Andris. Please check out my comment for my findings. – Omar Odaini May 01 '21 at 08:10
0

I'm new to react so I was expecting my code to wait and update state on first render. However, its expected not to have value on first render and the way to deal with it, is to basically, run the dependent code in another useEffect hook that has that state in its dependencies array. Here's the code:

import React, { useState, useEffect } from 'react'
import {getAllArchive} from '../Schemas/activitiesArchiveSchema';

const Stats = () => {
  const [Archives, setArchives] = useState();

  useEffect(() => {
    (async () => setArchives(await getAllArchive()))();
  }, []);

  useEffect(() => {
    // "dependent code"
    console.log(JSON.stringify(Archives))
  }, [Archives])

and obviously the first render is undefined but the second should have the value change.

Thanks

Omar Odaini
  • 101
  • 1
  • 7