简体   繁体   中英

Warning for 'exhaustive-deps' keeps asking for the full 'props' object instead of allowing single 'props' methods as dependencies

This question is related to the eslint-plugin-react-hooks

When I'm in CodeSanbox using a React Sandbox I can use single properties of the props object as dependencies for the useEffect hook:

Example 1:

useEffect(()=>{
  console.log('Running useEffect...');
  console.log(typeof(props.myProp));    // USING ONLY 'myProp' PROPERTY
},[ ]);                                 // EMPTY ARRAY

The example 1 gives me the following warning in CodeSandbox environment:

React Hook useEffect has a missing dependency: 'props.myProp'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps) eslint

And if I add [props.myProp] to the array, the warning goes away.

But the same example 1 in my local environment in VSCode, I get the following warning :

React Hook useEffect has a missing dependency: 'props'. Either include it or remove the dependency array. However, 'props' will change when any prop changes, so the preferred fix is to destructure the 'props' object outside of the useEffect call and refer to those specific props inside useEffect.eslint(react-hooks/exhaustive-deps)

Is asks me that I'm missing the full props object. And if I add [props.myProp] to the array, the warning DOES NOT go away. Although the code works as intended.

I would expect that I would get the same behavior that I get on CodeSandbox in my local environment in VSCode.

What could be happening? Is there any configuration I could change in eslint-plugin-react-hooks ?

PACKAGES

DEV:

"eslint": "^5.10.0",
"eslint-plugin-react": "^7.11.1",
"eslint-plugin-react-hooks": "^1.6.1",

REGULAR

"react": "^16.8.6",
"react-dom": "^16.8.6",

.eslintrc.json

{
  "root"  :true,
  "env": {
    "browser": true,
    "commonjs": true,
    "es6": true,
    "node": true
  },
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:import/errors"
  ],
  "parser":"babel-eslint",
  "parserOptions": {
    "ecmaVersion": 8,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx":true
    }
  },
  "plugins":[
    "react",
    "react-hooks"
  ],
  "rules": {
    "react/prop-types": 0,
    "semi": "error",
    "no-console": 0,
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn"
  },
  "settings": {
    "import/resolver" : {
      "alias" : {
        "map" : [
          ["@components","./src/components"],
          ["@constants","./src/constants"],
          ["@helpers","./src/helpers"]
        ],
        "extensions": [".js"]
      }
    }
  }
}

The answer to this question is somewhat answered here: https://github.com/facebook/react/issues/16265#issuecomment-517518539

The reason plugin sees it differently is because by doing props.whatever() you are actually passing props itself as a this value to whatever . So technically it would see stale props.

By reading the function before the call you're avoiding the problem.

Although the answer says that destructuring is the answer, there is a small caveat. Destructuring or reassigning will either have no effect except resolving the warning (99% of cases) or break your code. If you destructure or reassign, the function will have no this , and if that's not a problem then the warning was meaningless. Here's a demo of a contrived case where any of this matters.

function bark() {
  console.log(`${this.name} barked.`);
}

const mac = {
  name: "mac",
  bark
};

const cheese = {
  name: "cheese",
  bark
};

const DogBark = props => {
  useEffect(() => props.dog.bark(), [props.dog.bark]);

  return null;
};

const Dog = () => {
  const [dog, setDog] = React.useState(mac);

  useEffect(() => setDog(cheese), []);

  // will cheese bark?
  return (
    <DogBark dog={dog} />
  );
};

Cheese will not bark. The problem becomes worse when you start using useCallback :

const DogBarkByCallback = props => {
  const bark = React.useCallback(() => props.dog.bark(), [props.dog.bark]);
  // every dog should bark, and if the definition of 
  // bark changes even though the dog is the same, it should bark again
  useEffect(() => bark(), [props.dog, bark]); 

  return null;
};

In this case, mac barks twice because the callback doesn't change. Thus, the solution is either to make sure [props.dog] is in your dependency array, as the warning recommends, or to know you don't need this and destructure or reassign the value to circumvent the warning.

Demonstrated here in the console: https://codesandbox.io/s/exhaustive-deps-fn-mrdld

Did you considered destructuring the property?

const { myProp } = props
useEffect(()=>{
  console.log('Running useEffect...');
  console.log(typeof(myProp));    // USING ONLY 'myProp' PROPERTY
},[myProp]);  

I understood what was going on. It's not a bug (I think).

This code:

useEffect(()=>{
  function someFunction() {
    props.whatever();                  // CALLING A FUNCTION FROM PROPS
  }
},[ ]);

Results in this warning:

React Hook useEffect has a missing dependency: 'props'. Either include it or remove the dependency array. However, 'props' will change when any prop changes, so the preferred fix is to destructure the 'props' object outside of the useEffect call and refer to those specific props inside useEffect. (react-hooks/exhaustive-deps)eslint


And this code:

useEffect(()=>{
  function someFunction() {
    props.whatever;                          // ACCESSING A PROPERTY FROM PROPS
  }
},[]);

Results in this warning:

React Hook useEffect has a missing dependency: 'props.whatever'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)eslint


I'm not sure why, but the plugin see it differently when you're calling a method from props or if your acessing a property from props .

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