Ronald Zwiers
Ronald Zwiers

Reputation: 840

React Hooks in combination with Firebase data not showing on page load

I want to use the React Hooks functionality in combination with Firebase. But now when the data is set, the result is only visible when the DOM is being updated. My current code is:

import React, { useState, useEffect } from 'react';
import firebase, { getPivotFunction } from '../../firebase';

/**
* Return a styled component
*/
const ListCards = () => {
  const [data, setData] = useState([]);

  const userListsRef = firebase
    .database()
    .ref('userLists')
    .child('1234d343f');

  useEffect(() => {
    (async function() {
       try {
         const response = await getPivotFunction(userListsRef, 'lists');
         setData(response);
       } catch (e) {
         console.error(e);
       }
    })();
  }, []);

 /**
 * Return all list cards
 */
 return (
  <ul>
    {data.map(item => (
      <li key={item.time}>dummy text</li>
    ))}
  </ul>
 );
};

When the page is beeing rendered for the first time the 'dummy text' is not displayed, only when there is an update beeing triggered. My goal is to let 'dummy text' apear when the page is done loading and data not having a length of 0.

In this case getPivotFunction contains:

/** Get FireBase data based on a pivot table */
const getPivotFunction = (ref, target) => {
  let dataArray = [];

  ref.once('value', userInfo => {
    userInfo.forEach(function(result) {
      firebase
        .database()
        .ref(target)
        .child(result.key)
        .on('value', snapshot => {
          dataArray.push(snapshot.val());
        });
    });
  });

  return dataArray;
};

Please let me know

Upvotes: 1

Views: 1511

Answers (2)

Shubham Khatri
Shubham Khatri

Reputation: 281646

Your getPivotFunction is an asynchronous function which relies on callback and this using async await on isn't the right approach. You instead need to have a callback

/** Get FireBase data based on a pivot table */
const getPivotFunction = (ref, target, callback) => {
  const dataArray= [];
  ref.once('value', userChats => {
    var i = 0;
    userChats.forEach(function(result) {
      firebase
        .database()
        .ref(target)
        .child(result.key)
        .on('value', snapshot => {
          i++;
          dataArray.push(snapshot.val());
          if(i === userChats.length) {
             callback(dataArray)
          }
        });
    });
  });
};

and use it like

/**
* Return a styled component
*/
const ListCards = () => {
  const [data, setData] = useState([]);

  const userListsRef = firebase
    .database()
    .ref('userLists')
    .child('1234d343f');

  useEffect(() => {
      getPivotFunction(userListsRef, 'lists', (response) => {
         setData(response);
      });
  }, []);

 /**
 * Return all list cards
 */
 return (
  <ul>
    {data.map(item => (
      <li key={item.time}>dummy text</li>
    ))}
  </ul>
 );
};

Upvotes: 2

Colin Ricardo
Colin Ricardo

Reputation: 17239

Hooks aren't meant to work with async functions like that. Something like this should work:

const ListCards = () => {
  const [data, setData] = useState([]);
  const [loaded, setLoaded] = useState(false);

  ... 

  useEffect(() => {
    getPivotFunction(userListsRef, 'lists')
    .then(data => { setData(data); setLoaded(true)});
  }, []);
};

Then only render when loaded is true.

Upvotes: 0

Related Questions