Understanding the exhaustive-deps Eslint rule in React
The "react-hooks/exhaustive-deps" rule warns us when dependencies are missing in effect hooks. To get rid of the warning, move function or variable declarations useEffect
inside the hook, remember arrays and objects that change on each render, or disable the rule.
Here is an example of how the warning is caused.
import React, {useEffect, useState} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
// 👇️ objects/arrays are different on re-renders
// they are compared by reference (not by contents)
const obj = {country: 'Germany', city: 'Hamburg'};
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
// ⛔️ React Hook useEffect has a missing dependency: 'obj'.
// Either include it or remove the dependency array. eslintreact-hooks/exhaustive-deps
}, []);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
The problem is that we useEffect
are using the obj variable in the hook, but we are not including it in dependencies
the array.
The most obvious solution to this error is to add the obj variable to useEffect
the hook's dependencies array.
However, this will result in an error in this case because objects and arrays are compared by reference in JavaScript.
The obj variable is an object with the same key-value pairs on every re-render, but it points to a different location in memory every time, so it causes the equality check to fail and results in an infinite re-render loop.
Arrays are also compared by reference in JavaScript.
One way to resolve the warning "React Hook useEffect has a missing dependency" is to disable the eslint rule for a single line or the entire file.
import React, {useEffect, useState} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
// 👇️ objects/arrays are different on re-renders
const obj = {country: 'Germany', city: 'Hamburg'};
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
dependencies
The comment above the array disables the react-hooks/exhausting-deps rule for a single line.
When
useEffect
the hook is passed an empty array as the second argument, it will only be called when the component is mounted.
Another solution is to move the variable or function declaration useEffect
inside the hook.
import React, {useEffect, useState} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
useEffect(() => {
// 👇️ move object / array / function declaration
// inside of the useEffect hook
const obj = {country: 'Germany', city: 'Hamburg'};
setAddress(obj);
console.log('useEffect called');
}, []);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
We moved the object's variable declaration into useEffect
the hook.
This removes the warning, since the hook no longer depends on an external object.
Another solution that may be rarely used but is best to know about is to move the function or variable declaration out of the component.
import React, {useEffect, useState} from 'react';
// 👇️ move function/variable declaration outside of component
const obj = {country: 'Germany', city: 'Hamburg'};
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
}, []);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
This is helpful because the variables are not recreated every time the App component is re-rendered.
This variable will point to the same location in memory for all renderers, so
useEffect
there is no need to track it in their dependencies array.
Another solution is to use useMemo
a hook to get the memoized value.
import React, {useMemo, useEffect, useState} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
// 👇️ get memoized value
const obj = useMemo(() => {
return {country: 'Germany', city: 'Hamburg'};
}, []);
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
// 👇️ safely include in dependencies array
}, [obj]);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
We use useMemo
the hook to get a memoized value that doesn't change between renders.
useMemo
The hook accepts a function that returns a value to memoize and an array of dependencies as arguments. The hook only recalculates the memoized value if one of the dependencies changes.
If you're using a function, you'd use useCallback
the hook to get a memoized callback that doesn't change between renders.
import React, {useMemo, useEffect, useState, useCallback} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
// 👇️ get memoized callback
const sum = useCallback((a, b) => {
return a + b;
}, []);
// 👇️ get memoized value
const obj = useMemo(() => {
return {country: 'Germany', city: 'Santiago'};
}, []);
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
console.log(sum(100, 100));
// 👇️ safely include in dependencies array
}, [obj, sum]);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
useCallback
The hook accepts an inline callback function and an array of dependencies, and returns a memoized version of the callback that only changes when one of the dependencies changes.
If none of the suggestions apply to your use case, we can always eliminate the warning with a comment.
import React, {useEffect, useState} from 'react';
export default function App() {
const [address, setAddress] = useState({country: '', city: ''});
const obj = {country: 'Chile', city: 'Santiago'};
useEffect(() => {
setAddress(obj);
console.log('useEffect called');
// 👇️ disable the rule for a single line
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div>
<h1>Country: {address.country}</h1>
<h1>City: {address.city}</h1>
</div>
);
}
For reprinting, please send an email to 1244347461@qq.com for approval. After obtaining the author's consent, kindly include the source as a link.
Article URL:https://www.jiyik.com/en/xwzj/web_9581.html
Related Articles
How to avoid cross-origin (CORS) issues in React/Next.js
Publish Date:2025/03/17 Views:166 Category:NETWORK
-
In this article, we will introduce how to avoid cross-origin (CORS) issues in React/Next.js. Cross-origin resource sharing (CORS) is a protocol that defines how web requests should be handled when crossing different URLs.
React Tutorial - Transferring Props
Publish Date:2025/03/16 Views:185 Category:React
-
React transfers Props. Props are generated when components are encapsulated. Components expose some properties (Props) to the outside world to complete some functions.
React Tutorial: Props Anti-Pattern
Publish Date:2025/03/16 Views:183 Category:React
-
React's Props anti-pattern, using Props to generate state in getInitialState is an anti-pattern - Anti-Pattern.
React Tutorial - Props Validation
Publish Date:2025/03/16 Views:99 Category:React
-
Props validation is a very useful way to use components correctly. It can avoid many bugs and problems as your application becomes more and more complex. In addition, it can make your program more readable.
React tutorial: Types of Props for child components
Publish Date:2025/03/16 Views:170 Category:React
-
Usually, the child components of a React component are a group, that is, the child components are an array. Introduction to Type of the Children Props.
How to solve the error Uncaught TypeError: Cannot read properties of undefined in
Publish Date:2025/03/16 Views:150 Category:React
-
In the process of React development, we often encounter some errors. Here we look at an error reported in App.js. The error is as follows: App.js:69 Uncaught TypeError: Cannot read properties of undefined (reading 'setState') at onInput
Why do you need to bind event handlers in React Class Components?
Publish Date:2025/03/16 Views:58 Category:React
-
When using React, we must have come across control components and event handlers. We need to use `.bind()` in the constructor of the custom component to bind these methods to the component instance. As shown in the following code:
Solution to the error "does not contain a default export" in React
Publish Date:2025/03/16 Views:187 Category:React
-
When we try to use `default import` to import from a module that does not have a `default export`, we get a "does not contain a default export" error. To fix the error, make sure the module has named exports and wrap the import in curly braces, e.g.
Error in React: Attempted import error 'X' is not exported from Solution
Publish Date:2025/03/16 Views:76 Category:React
-
In React, the error “Attempted import error 'X' is not exported from” in React.js occurs when we try to import a named import that does not exist in the specified file. To fix the error, make sure the module has named exports and you have not obfu