Home > Mobile >  useeffect infinite loop even though state data is not changing
useeffect infinite loop even though state data is not changing

Time:08-18

My program goes into an infinite loop constantly calling useEffect() everytime I start the app. I have one state that I don't think is changing other than in the retrieveItemStatus() function so I'm confused on why its going into a loop like it is.

const App = () => {
  var items;
  const [itemStatuses, updateStatuses] = useState({});

  const retrieveItemStatus = async () => {
    var tempStatuses;
    try {
      const value = await AsyncStorage.getItem("@item_Statuses");
      if (value !== null) {
        tempStatuses = await JSON.parse(value);
        //console.log("123456");
      } else {
        tempStatuses = await JSON.parse(
          JSON.stringify(require("../default-statuses.json"))
        );
      }
      updateStatuses(tempStatuses);
    } catch (error) {}
  };
  retrieveItemStatus();

  useEffect(() => {
    const copyData = async () => {
      const itemsCopy = [];

      const coll = await collection(db, "Items");
      const querySnapshots = await getDocs(coll);
      const docsArr = querySnapshots.docs;
      docsArr.map((doc) => {
        var data = doc.data();
        if (itemStatuses[data.name] === "locked") return;
        itemsCopy.push(data);
      });
      items = itemsCopy;
      //getItems([...itemsCopy]);
    };

    copyData();

  }, [itemStatuses]);

  return (
    <View style={styles.container}>
      <Text>temp.......</Text>
    </View>
  );
};

CodePudding user response:

It has nothing to do with useEffect. You're calling retrieveItemStatus unconditionally every time your component function is called to render the componennt. retrieveItemStatus calls updateStatuses which changes state. You see your useEffect callback get run repeatedly as a side-effect of that, because your useEffect callback has itemStatuses as a dependency.

I assume you only need the itemStatuses to get fetched once. If so, put the call in a useEffect callback with an empty dependency array:

useEffect(retrieveItemStatus, []);

CodePudding user response:

@T.J. Crowder's answer is correct but I want to clarify a small point, so you understand why your useEffect didn't stop running.

As you you know, when the dependency in dependency array changes, useEffect runs. But the data in your itemStatuses doesn't change right(according to you)? So why does useEffect re-runs? Let's look at the below example:

const obj1 = {};
const obj2 = {};
const obj3 = {a:2};
const obj4 = {a:2};


console.log(obj1 === obj2)
console.log(obj3 === obj4)

console.log(obj3.a === obj4.a)

As you can see javascript doesn't think that an empty object is strictly equal to another empty object. It is because these objects refer to the different locations in memory regardless of their content.

So that's why every time retrieveItemStatus ran, it updated itemStatuses. Then because itemStatuses got updated(although the value is same), useEffect triggered a re-render, so again everything started all over.

CodePudding user response:

Main reason is in calling retrieveItemStatus(); without any event. If you want to call this function when page loading, you should like this.

...
useEffect(() => {
  retrieveItemStatus()
}, [])
...

This will fix loop issue. :)

  • Related