Home > front end >  React Hook useEffect has missing dependencies and some weird error
React Hook useEffect has missing dependencies and some weird error

Time:03-23

I'm trying to filter the array by multiple conditions. This is working but getting few errors.

Here is the App.js code

import "./styles.css";
import keywords from "./keywords.json";
import { useEffect, useState } from "react";

export default function App() {
  const [finalData, setFinalData] = useState([]);
  const [category, setCategory] = useState("");
  const [range, setRange] = useState(50);

  const filterByCategory = (keywords) => {
    return keywords.filter((item) => item.type.includes(category));
  };

  const filterByRange = (keywords) => {
    return keywords.filter((item) => item.search <= range);
  };

  const funcRange = (event) => {
    setRange(event.target.value);
  };

  useEffect(() => {
    let result = keywords;
    result = filterByRange(result);
    result = filterByCategory(result);
    setFinalData(result);
  }, [category, range]);

  return (
    <div className="App">
      <h1>My App</h1>
      <input
        type="range"
        min={50}
        max={100}
        value={range}
        onChange={funcRange}
      />
      <select
        name="category"
        id="category"
        onChange={(event) => setCategory(event.target.value)}
      >
        {[...keywords].map((option) => (
          <option value={option.type} key={option.id}>
            {option.type}
          </option>
        ))}
      </select>
      <p>{category}</p>
      <h3>{range}</h3>
      {finalData.map((item) => (
        <>
          <li key={item.id}>
            {item.name} - {item.search} - {item.type}
          </li>
        </>
      ))}
    </div>
  );
}

Here is keywords.json file

[
  {
    "name": "google",
    "search": 50,
    "type": "search"
  },
  {
    "name": "google",
    "search": 80,
    "type": "image"
  },
  {
    "name": "google",
    "search": 50,
    "type": "maps"
  },
  {
    "name": "yahoo",
    "search": 60,
    "type": "search"
  },
  {
    "name": "youtube",
    "search": 75,
    "type": "search"
  },
  {
    "name": "youtube",
    "search": 65,
    "type": "video"
  }
]

Everything is working perfectly but I'm getting this error in console.

React Hook useEffect has missing dependencies: 'filterByCategory' and 'filterByRange'. Either include them or remove the dependency array. (react-hooks/exhaustive-deps)

If I add 'filterByCategory' and 'filterByRange' to the useEffect dependency, I'm getting the below error.

Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

Here is the enter image description here

CodePudding user response:

The infinite recursion occurs because you haven't memoized the inner functions with useCallback; their identity changes on each render, and the effect fires, etc.

However, you shouldn't do that here – instead of using an effect and state to compute the filtered data, do it with useMemo, since it's strictly derivable from your current state.

export default function App() {
  const [category, setCategory] = useState("");
  const [range, setRange] = useState(50);

  const funcRange = (event) => {
    setRange(event.target.value);
  };
  
  const finalData = React.useMemo(() => {
    return keywords
      .filter((item) => item.search <= range)
      .filter((item) => item.type.includes(category));
  }, [keywords, category, range]);
  // ...
}

CodePudding user response:

Most people will advice to using useMemo, for something like this.

Personally I think in most cases it's not required. The reason why the Lint errors is there is because the function will be created every render, and that's why the advice for useMemo.

But there is a much easier way to prevent a function been re-created on each render, just don't put it inside the function.

There are a couple of nice advantages here too, if you think about how React handles hooks, it works like a bit of a stack, it's the reason why Hooks have to be kept in the same order. So as well as avoiding the performance hit of using a useMemo, you get the advantage of not worrying about Hook ordering, and that can be handy for function early termination that would normally break the hooks.

So in your example you only need to change a few things..

First move the two function outside of the App function->

const filterByCategory = (keywords, category) => {
  return keywords.filter((item) => item.type.includes(category));
};

const filterByRange = (keywords, range) => {
  return keywords.filter((item) => item.search <= range);
};

export default function App() {.......

You will notice you have to add the extra parameters, but that in itself is not a bad thing either, as you have now made the code more re-usable.

Of course next you just have to add those parameters at the calling end.

result = filterByRange(result, range);
result = filterByCategory(result, category);

Updated Sandbox -> Sandbox

  • Related