Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix warning "function -- makes the dependencies of useEffect Hook change on every render"?

How I can fix the warning 'createGraphics' function makes the dependencies of useEffect Hook (at line 77) change on every render. Move it inside the useEffect callback. Alternatively, wrap the 'createGraphics' definition into its own useCallback() Hook.

And also when I try to make empty dependency array I have this warning - React Hook React.useEffect has a missing dependency: 'createGraphics'. Either include it or remove the dependency array

import React from "react";
import * as d3 from "d3";
import { GraphicsItem, StatsWrapper } from "../style";
import "../assets/style.css";

export const GraphicItem = ({ graphNames, screenSize }) => {
  const createGraphics = () => {
    let randArray = function () {
      for (var i = 0, array = new Array([]); i < 19; i++) {
        array.push(Math.floor(Math.random() * 19 + 1));
      }
      return array;
    };
    let initRandArray = randArray();

    let w = screenSize >= 1920 ? 220 : 150;
    let h = 130;
    let barPadding = 1;
    let mAx = d3.max(initRandArray);
    let yScale = d3.scaleLinear().domain([0, mAx]).range([0, h]);

    let svg1;

    svg1 = d3.select(`.item0`).append("svg").attr("width", w).attr("height", h);

    function setSvgItem(svg) {
      svg
        .selectAll("rect")
        .data(initRandArray)
        .enter()
        .append("rect")
        .attr("x", function (d, i) {
          return i === 18
            ? screenSize >= 1920
              ? "61"
              : "41.5"
            : i === 19
            ? screenSize >= 1920
              ? "136"
              : "93"
            : i * (w / initRandArray.length);
        })
        .attr("y", function (d) {
          return h - yScale(d);
        })
        .attr("width", w / initRandArray.length - barPadding)
        .attr("height", function (d) {
          return yScale(d);
        })
        .attr("fill", function (d, index) {
          return index === 19
            ? "rgb(246 185 46)"
            : index === 18
            ? "rgb(0 212 198)"
            : "rgb(rgb 16 19 " + d * 100 + ")";
        });
    }

    const setSvgElements = () => {
      setSvgItem(svg1);
    };

    return setSvgElements();
  };

  React.useEffect(() => {
    createGraphics();
  }, [createGraphics]);

  return (
    <>
    ///////
    </>
  );
};

like image 787
wefwe fwef Avatar asked Dec 16 '20 10:12

wefwe fwef


People also ask

How do I get rid of useEffect warning?

Solution 1: Passing a stable reference to useEffect This would remove the warning because the hook no longer had a dependency on the object because it was declared inside of it. Alternatively, we can also move the declaration of the function or variable outside our component.

How do you fix missing dependency warning when using useEffect React?

To solve the "react hook useeffect has a missing dependency" warning, you can: Add the missing dependency. Move the dependency inside the useEffect hook. Disable the ESLint rule.

How do you make useEffect run on every render?

Side Effect Runs After Every Render The first is the default case. If you do not pass the dependency array to the useEffect hook, the callback function executes on every render. Thus React will run the side effect defined in it after every render. useEffect(() => { // Side Effect });

What happens if you don't specify the dependencies list in useEffect?

If you don't specify it, the effect runs after each render. If it's empty ( [] ), the effect runs once, after the initial render.


2 Answers

I think you do not need to add createGraphics to the useEffect() dependency array but, if you have to, you can wrap the function in a useCallback() hook:

export const GraphicItem = ({ graphNames, screenSize }) => {
  const createGraphics = React.useCallback(() => { 
    /* function body */ 
  }, [screenSize]);

  React.useEffect(() => {
    createGraphics();
  }, [createGraphics]);

  return (
    <>
    ///////
    </>
  );
};

Another solution would be declaring createGraphics outside the component, so that it is not re-instantiated every time the componet re-renders. In this case you'll have to slightly modify the function so that it accepts one arguments (screenSize), which will be passed to it when you call the function in the useEffect hook:

function createGraphics(screenSize) {
    /* function body */
}

export const GraphicItem = ({ graphNames, screenSize }) => {
  React.useEffect(() => {
    createGraphics(screenSize);
  }, [screenSize]);

  return (
    <>
    ///////
    </>
  );
};
like image 144
secan Avatar answered Oct 16 '22 18:10

secan


React is complaining because createGraphics is defined in the main body of your component. This means that every time your component re-renders, createGraphics is re-created as a new function reference along with it.

Notice how you've specified createGraphics as a dependency in your useEffect? This dependency array is used for memoisation. You're saying "hey React, only do this effect if createGraphics changes". But it is changing every render for the reason described above, hence the warning.

So you can solve this by doing:

React.useEffect(() => {
    const createGraphics = () => {
        // your function using screenSize here
    }

    createGraphics();
  }, [screenSize]);

or

const createGraphics = React.useCallback(() => {
    // your function using screenSize here
  }, [screenSize]);

// use createGraphics elsewhere

This way, only changes in screenSize will create new createGraphics functions.

About "React Hook React.useEffect has a missing dependency: 'createGraphics'", this is warning you that the empty dependency list implies createGraphics will never update, even if screenSize changes. In otherwords, createGraphics will always reference the first instance of screenSize the component gets on mount.

like image 31
Asher Lim Avatar answered Oct 16 '22 19:10

Asher Lim