With React 16.8.6 (it was good on previous version 16.8.3), I get this error when I attempt to prevent an infinite loop on a fetch request
./src/components/Bu
const [mount, setMount] = useState(false)
const fetchBusinesses = () => {
//function defination
}
useEffect(() => {
if(!mount) {
setMount(true);
fetchBusinesses();
}
},[fetchBusinesses]);
This is solution is pretty simple and you don't need to override es-lint warnings. Just maintain a flag to check whether component is mounted or not.
Just pass the function as the argument in the array of useEffect...
useEffect(() => {
functionName()
}, [functionName])
You can remove the 2nd argument type array []
but the fetchBusinesses()
will also be called every update. You can add an IF
statement into the fetchBusinesses()
implementation if you like.
React.useEffect(() => {
fetchBusinesses();
});
The other one is to implement the fetchBusinesses()
function outside your component. Just don't forget to pass any dependency arguments to your fetchBusinesses(dependency)
call, if any.
function fetchBusinesses (fetch) {
return fetch("theURL", { method: "GET" })
.then(res => normalizeResponseErrors(res))
.then(res => res.json())
.then(rcvdBusinesses => {
// some stuff
})
.catch(err => {
// some error handling
});
}
function YourComponent (props) {
const { fetch } = props;
React.useEffect(() => {
fetchBusinesses(fetch);
}, [fetch]);
// ...
}
just disable eslint for the next line;
useEffect(() => {
fetchBusinesses();
// eslint-disable-next-line
}, []);
in this way you are using it just like a component did mount (called once)
updated
or
const fetchBusinesses = useCallback(() => {
// your logic in here
}, [someDeps])
useEffect(() => {
fetchBusinesses();
// no need to skip eslint warning
}, [fetchBusinesses]);
fetchBusinesses will be called everytime someDeps will change
The solution is also given by react, they advice you use useCallback
which will return a memoize version of your function :
The 'fetchBusinesses' function makes the dependencies of useEffect Hook (at line NN) change on every render. To fix this, wrap the 'fetchBusinesses' definition into its own useCallback() Hook react-hooks/exhaustive-deps
useCallback
is simple to use as it has the same signature as useEffect
the difference is that useCallback returns a function.
It would look like this :
const fetchBusinesses = useCallback( () => {
return fetch("theURL", {method: "GET"}
)
.then(() => { /* some stuff */ })
.catch(() => { /* some error handling */ })
}, [/* deps */])
// We have a first effect thant uses fetchBusinesses
useEffect(() => {
// do things and then fetchBusinesses
fetchBusinesses();
}, [fetchBusinesses]);
// We can have many effect thant uses fetchBusinesses
useEffect(() => {
// do other things and then fetchBusinesses
fetchBusinesses();
}, [fetchBusinesses]);
Actually the warnings are very useful when you develop with hooks. but in some cases, it can needle you. especially when you do not need to listen for dependencies change.
If you don't want to put fetchBusinesses
inside the hook's dependencies, you can simply pass it as an argument to the hook's callback and set the main fetchBusinesses
as the default value for it like this
useEffect((fetchBusinesses = fetchBusinesses) => {
fetchBusinesses();
}, []);
It's not best practice but it could be useful in some cases.
Also as Shubnam wrote, you can add below code to tell ESLint to ignore the checking for your hook.
// eslint-disable-next-line react-hooks/exhaustive-deps