0

Im having some trouble with realtime database and react native. I have the following useEffect in a component that is supposed to listen for changes and then update state as required, I then use that state to populate a list.

The component gets a data object passed as a prop, the data object contains a string array called members that contains uuids, I am trying to iterate over those to get the attached user from realtime db and then save those objects to a state array.

const myComponent = ({ data }) => {
 const [users, setUsers] = useState([]);
 
 useEffect(() => {
            const userArr = [];
            data.map(item => {
                item.members.forEach((username: string) => {
                    database()
                        .ref(`users/${username}`)
                        .on('value', snapshot => {
                            userArr.push(snapshot.val());
                        });
                });
            });
            setUsers(userArr);
        };
    }, []);

return (
  <>
   {users} <-----  this is in a flatlist
  </>
 );
}

It works eventually after refreshing the screen about 5 times. Any help would be greatly appreciated.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807

3 Answers3

1

Your database call may be asynchronous, which is causing the code inside the useEffect to act a little funny. You could push all those database calls (while iterating through item.members) into an array, and then do Promise.all over the array. Once the promises are resolved, you can then set the users.

Hope this helps!

Amit Maraj
  • 344
  • 1
  • 5
1

The simplest way to get some data to show is to move update the state right after you add an item to the array:

useEffect(() => {
  const userArr = [];
  data.map(item => {
      item.members.forEach((username: string) => {
          database()
              .ref(`users/${username}`)
              .on('value', snapshot => {
                  userArr.push(snapshot.val());
                  setUsers(userArr); // 
              });
          });
      });
  };
}, []);

Now the UI will update each time that a user is loaded from the database.

I also recommend reading some more about asynchronous loading, such as in Why Does Firebase Lose Reference outside the once() Function?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
0

add an async function inside useEffect and call it

useEffect(() => {
    const getUsers = async () => {
       const userArr = [];
       data.....
     
       //wait for it with a promise
       Promise.all(userArr).then(array => setUsers(array))
    })
   getUsers()
}, [])

not sure if the function needs to be async

codmitu
  • 636
  • 7
  • 9