简体   繁体   中英

React Hook UseEffect in combination with Firebase creating infinite loop

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM