Home > Back-end >  useEffect received a final argument during this render
useEffect received a final argument during this render

Time:08-26

I am getting this warning:

Warning: useEffect received a final argument during this render, but not during the previous render. Even though the final argument is optional, its type cannot change between renders.

warning screenshot here

//importing ...

const Relevance = () => {
  const { data, setData } = useContext(defaultData);

  if (data.length > 0) {
    const Relevance = data.map((d) => {
      return d.relevance;
    });

    const maxValue = Math.max(...Relevance);

    let HashRelevance = new Array(maxValue   1).fill(0);
    for (let i = 0; i < Relevance.length; i  ) {
      if (Relevance[i] !== null) {
        HashRelevance[Relevance[i]]  ;
      }
    }

    var keyRelevance = [];
    var valueRelevance = [];
    for (let i = 0; i < HashRelevance.length; i  ) {
      if (HashRelevance[i] !== 0) {
        keyRelevance.push(i);
        valueRelevance.push(HashRelevance[i]);
      }
    }
  }
  const [keyRelevanceState, setKeyIntenstityState] = useState([]);
  const [valueRelevanceState, setValueIntenstityState] = useState([]);
  useEffect(() => {
    setKeyIntenstityState(keyRelevance);
  }, keyRelevance);

  useEffect(() => {
    setValueIntenstityState(valueRelevance);
  }, valueRelevance);
  if (valueRelevanceState !== undefined && valueRelevanceState.length > 0) {
    return (
        returning component...
    )
};

export default Relevance;

What is the error about?

CodePudding user response:

That error is telling you that you're not passing a consistent value to useEffect as its final (second) argument (the optional dependency array) between renders. The dependency array argument you pass useEffect must either always be an array of dependencies (with the same length), or always be undefined (because you left it off, usually), on every render of your component.

You have this code:

if (/*...a condition...*/) {
    // ...
    var keyRelevance = [];
    // ...
}
// ...
useEffect(() => {
   // ...
}, keyRelevance);

That's functionally identical to:

var keyRelevance;              // ***
if (/*...a condition...*/) {
    // ...
    keyRelevance = [];         // ***
    // ...
}
// ...
useEffect(() => {
   // ...
}, keyRelevance);

That means you're declaring a keyRelevance variable that will initially have the value undefined, and then only assigning an array to it if a condition is met. Then you're using keyRelevance as the dependencies array.

The second argument to useEffect should be an array of dependencies, not just a single dependency, so wrap keyRelevance in an array:

useEffect(() => {
    setKeyIntenstityState(keyRelevance);
}, [keyRelevance]);
// ^            ^

More in the documentation.

But separately, since you're creating a new array every time, that would cause the effect to change every time. Instead, memoize the creation of keyRelevance (and similar) using useMemo or useRef (since useMemo's documentation says it's just for performance optimization, and in your case you need to memoize the value for correctness, not just optimization).

For instance:

const relevanceInfo = useRef(null);
// (Probably put this condition in a function)
if (!relevanceInfo ||
    data.length !== relevanceInfo.sourceData.length || 
    data.some((d, index) => d.relevance !== relevanceInfo.sourceData[index].relevance)) {
    relevanceInfo.keyRelevance = /* ...build the array... */;
    relevanceInfo.sourceData = data;
}

// ...
useEffect(() => {
    // ...
}, [relevanceInfo.keyRelevance]);

...or similar.


Side note: I wouldn't declare the variable inside the if block and then use it outside the if block. Instead, declare it in the top scope where it'll be used (in this case function scope). (Also, I suggest using let and const, not var; var is effectively deprecated and shouldn't be used in new code.)

CodePudding user response:

Final value, (second parameter) of the useEffect should be in array of different values or empty array. You are providing a valueRelevance as final value of useEffect which itself an array but not in array , like below.

useEffect(() => {
    setKeyIntenstityState(keyRelevance);
}, [valueRelevance]);

Or,

 useEffect(() => {
        setKeyIntenstityState(keyRelevance);
    }, [param1, param2]);

  • Related