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 passingprops
itself as athis
value towhatever
. 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.