Things to be careful when using useEffect
- always specify a dep array
- beware of array, objects as dependancy
Tips
1. Making API requests -- The better way of using useEffect
// handle component mount & unmount
useEffect(() => {
let mounted = true;
getList().then((items) => {
if (mounted) {
setList(items);
}
});
// onUnmount cancel the request
return () => (mounted = false);
}, []);
Above solution will not work for handleSubmit
, since it is not an effect. You can’t return a function to set the value to false when it is unmounted. Further, it would be inefficient to add the same check to every function
So better solution would be useRef. The useRef Hook will preserve a variable for the lifetime of the component.
const mounted = useRef(true);
useEffect(() => {
mounted.current = true;
if (list.length && !alert) {
return;
}
getList().then((items) => {
if (mounted.current) {
setList(items);
}
});
return () => (mounted.current = false);
}, []);
so using this let's make a data fetching hook:
import React, { useState, useEffect, useRef, useLayoutEffect } from "react";
const useCallbackRef = (callback) => {
const callbackRef = useRef(callback);
// synchronous vairant useEffect
useLayoutEffect(() => {
callbackRef.current = callback;
}, [callback]);
return callbackRef;
};
const mounted = useRef(true);
export const useFetch = (options) => {
const [data, setData] = useState(null);
const savedOnSuccess = useCallbackRef(options.onSuccess);
useEffect(() => {
if (options.url) {
let mounted.current = false;
fetch(options.url)
.then((response) => response.json())
.then((json) => {
if (mount.current) {
savedOnSuccess.current?.(json);
setData(json);
}
});
return () => mounted.current = false
}
}, [options.url]);
return {
data,
};
};
We can use hooks like useSWR
https://github.com/vercel/swr to make API calls that eliminate above issues and add functionalities like caching
2. Use Effect with setInterval
Depending On State Mutated In The useEffect
const [number, setNumber] = useState(0);
useEffect(() => {
setInterval(() => {
// use Update function of setState
setNumber((prev) => prev + 1);
}, 1000);
}, []);