1

I'm working on a project that uses Firebase and React hooks. Before the web application is loaded i want to get all the data from Firebase by running the query as shown below.

const [lists, setLists] = useState([]);

useEffect(() => {
  const dataArray = [];
  /** handleWidgets */
  listsRef
    .once('value', snap => {
      snap.forEach(function(result) {
        firebase
          .database()
          .ref('lists')
          .child(result.key)
          .on('value', snap => {
            if (snap.val()) dataArray.push(snap.val());
          });
      });
    })
    .then(function() {
      setLists(dataArray);
    });
}, [lists]);

For some reason the useEffect is always running and creating a huge performance issue. Is there a better way to use Firebase queries with React Hooks like useEffect? Now if lists is changed or not the useEffect is always running.

1 Answer 1

3

UPDATED:

A couple of things:

1) Your useEffect is subscribing to lists which is being set within this useEffect, so it's triggering a re-run.

2) You're attempting to update the item and then re-fetch all of the data including the updated item. You don't need to do this. Once you have your "initial state" from Firebase, all of the modifications can happen to that list within state. Yes, you'll call to do the add/update/delete, but you don't need to call to get a brand new list each time because you know what information you've changed and can simply update your state list to reflect this while also calling to actually update the underlying data so that when you navigate away your list from Firebase reflects the list that was in state.

SO!

Remove the lists from the [] at the end so your code so it only runs on mount and looks like the following:

const [lists, setLists] = useState([]);

useEffect(() => {
  const dataArray = [];
  /** handleWidgets */
  listsRef
    .once('value', snap => {
      snap.forEach(function(result) {
        firebase
          .database()
          .ref('lists')
          .child(result.key)
          .once('value', snap => {
            if (snap.val()) dataArray.push(snap.val());
          });
      });
    })
    .then(function() {
      setLists(dataArray);
    });
}, []); // removed lists from subscription []

Then, let's say in an add method, it would look something like the following:

addItem = listItem => {
    // make copy of array in state
    const newLists = [...lists];

    // add item to list
    newLists.push(listItem);

    // update list in DB with firebase
    /* firebase call here with new list item */

    // update state lists with new array that has new item
    setLists(newLists)
}

And so on and so forth from the update/delete methods. You're going to just use that state value without ever calling Firebase for an updated list because you already have it.

Sign up to request clarification or add additional context in comments.

4 Comments

The thing is that i want to update the DOM when e.g. the user inserts a new list item or changes the title. Then i want to re-run the query and get the new data from Firebase.
When the user updates a list value or inserts a new item, is it calling Firebase as well to update the underlying data?
Yes it will get the new data but then the dom needs to be re-rendered
I have updated my answer - let me know if that still doesn't answer/solve your question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.