Why useEffect makes infinitive loop if pass the second param as array and inside put empty object

I have object with filter params for API and this object I pass to useEffect.

    let dataForFilter = typeof defaultFormData[someKey] !== 'undefined'
    ? defaultFormData[someKey]
    : {};

    for (let key in props.route.params) {
        if (props.route.params.hasOwnProperty(key)) {
            dataForFilter[key] = props.route.params[key];
        }
    }

    useEffect(() => {
        async function fetchData() {
            const body = {
               ...dataForFilter,
            };
            loadData(url, body);
        }
        fetchData();
    }, [dataForFilter]);

By default the object is empty but this makes infinite loop if I pass empty object in array as second parameter.
I don’t understand why? Please could somebody explain me why and how this solve.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Every time the function runs, it creates a new empty object here:

let dataForFilter = typeof defaultFormData[someKey] !== 'undefined'
    ? defaultFormData[someKey]
    : {};

So the dependency array’s values change every render, if defaultFormData[someKey] doesn’t exist. The empty object isn’t equal to itself.

console.log([{}] === [{}]);
console.log({} === {});

Create the object outside the function instead, so that its reference is stable.

const emptyObj = {};
const MyComponent = ({ defaultFormData }) => {
  // ...
  let dataForFilter = typeof defaultFormData[someKey] !== 'undefined'
    ? defaultFormData[someKey]
    : emptyObj;

Method 2

In your useEffect, call a function to rerender the component. In your useEffect dependencies (the array at the end), you passed in dataForFilter as dependency. That means, whenever dataForFilter changes, the useEffect will be called again. But since the useEffect makes the component rerender and dataForFilter is not defined as state but as normal variable inside the component, it will be defined again with another value (Notice: Even an object with the same values is not the same object as before). If you want any useEffect to be called once when the component renders, pass an empty array as dependencies like this:

let dataForFilter = typeof defaultFormData[someKey] !== 'undefined' // <-- dataForFilter gets evaluated again and changes its value, which calls the useEffect
    ? defaultFormData[someKey]
    : {};

    for (let key in props.route.params) {
        if (props.route.params.hasOwnProperty(key)) {
            dataForFilter[key] = props.route.params[key];
        }
    }

    useEffect(() => {
        async function fetchData() {
            const body = {
               ...dataForFilter,
            };
            loadData(url, body); // <-- You rerender the component somewhere in this function, dataForFilter gets defined again and is another object (with the same value BUT still another object)
        }
        fetchData();
    }, []); // <-- Empty array as dependency, only gets called once


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x