JIYIK CN >

Current Location:Home > Learning > WEB FRONT-END > React >

Understanding the exhaustive-deps Eslint rule in React

Author:JIYIK Last Updated:2025/03/17 Views:

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 useEffectinside 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 useEffectare using the obj variable in the hook, but we are not including it in dependenciesthe array.

The most obvious solution to this error is to add the obj variable to useEffectthe 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>
  );
}

dependenciesThe comment above the array disables the react-hooks/exhausting-deps rule for a single line.

When useEffectthe 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 useEffectinside 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 useEffectthe 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 useEffectthere is no need to track it in their dependencies array.

Another solution is to use useMemoa 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 useMemothe hook to get a memoized value that doesn't change between renders.

useMemoThe 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 useCallbackthe 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>
  );
}

useCallbackThe 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.

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.

Scan to Read All Tech Tutorials

Social Media
  • https://www.github.com/onmpw
  • qq:1244347461

Recommended

Tags

Scan the Code
Easier Access Tutorial