How do you fix 'React Hook useEffect has a missing dependency:' warnings? - reactjs

I get two warnings from these two useEffects. I am learning React.js and this is my first time dealing with this issue.
const fetchShippingCountries = async (checkoutTokenId) => {
const { countries } = await commerce.services.localeListShippingCountries(checkoutTokenId)
useEffect(() => {
fetchShippingCountries(checkoutToken.id);
}, []);
const fetchShippingOptions = async (checkoutTokenId, country, region = null) => {
const options = await commerce.checkout.getShippingOptions(checkoutTokenId, { country, region });
setShippingOptions(options);
setShippingOption(options[0].id);
}
useEffect(() => {
if(shippingSubdivision) fetchShippingOptions(checkoutToken.id, shippingCountry, shippingSubdivision);
}, [shippingSubdivision]);
React Hook useEffect has a missing dependency: 'checkoutToken.id'.
Either include it or remove the dependency array
React Hook useEffect has missing dependencies: 'checkoutToken.id' and 'shippingCountry'. Either include them or remove the dependency array

React is asking you to pass the 'checkoutToken.id' and 'shippingCountry' variables into the useEffect dependency array. useEffect is always called whenever the variables within dependency array change. Since you're using these two variables within useEffect, React is warning you that a change in them will not trigger the useEffect.
It's a part of the best practices to add all the variables being used by the useEffect function into the dependency array. This is to make sure you are keeping complete control over the changes within your React app.

Related

Warning 'React hook useEffect has a missing dependency'

In a React app I get this warning on a few components in the useEffect function. I have seen other SO questions but still cant see a fix.
React Hook useEffect has a missing dependency: 'digiti' and 'time'. Either include it or remove the dependency array
const GenerateNumber = (props) => {
const [number, setNumber] = useState(0);
// add side effect to component
useEffect(() => {
const interval = setInterval(
() => setNumber(Math.floor(Math.random() * 9 + 1)),
50
);
setTimeout(() => { clearInterval(interval); setNumber(props.digiti); }, props.times * 100);
}, []);
return (
<span className='digit'>{number}</span>
);
}
This is something the react hooks exhaustive deps explain. In general, your dependency array should include all values used in the dependency array, however when you do this with something like setNumber, your useEffect hook will run infinitely as each change of setNumber triggers a new render (and each new render triggers setNumber, see the problem there?).
Your actual error, with the prop values of both digiti and times aim at you adding these two values to the dependency array, which would case the useEffect hook to run again every time these props change. It is up to you if this is intended behavior.
What is actually documented in the dependency array documentation is that it is intended behavior to leave the array empty to have the useEffect hook run exactly once.

How to stop calling the api again and again using react useEffect?

I am using the redux toolkit, after adding the product dependency it is calling the API rapidly. How can I stop calling the API again and again?
There are two solutions:
Remove it as a dependency. if you only want dispatch when component first time render then use empty brackets []
Example:
useEffect(() => {
dispatch(fetchProducts());
}, []);
Use the useMemo hook, then the component will be rendered only the products have been changed.
Remove it as a dependency, if you only want to call it once when the component mounts just have an empty dependency. like this...
useEffect(() => {
dispatch(fetchProducts());
}, []);
remove dispatch in dependency:
useEffect(() => {
}, [products])

React Hooks: useEffect with dependecy also called when component mounts

In React, you can use useEffect() hook with a dependency on it.
const [data, setData] = useState();
useEffect(() => {
console.log(data.test.test);
}, [data]);
So I would assume that this useEffect is just called when the data is changed.
So let´s assume I would make an api call and use setData(response.data).
Then the useEffect() should be triggerd, since the data state is a dependecy.
Then the console.log(data.tes.test) would be working, since I got the right data.
However, I get an undefined error, which comes from the fact that useEffect() is also called initially.
How can I avoid this? This is pretty annoying and in my mind not a good design with regard to adding a dependency.
You have two solutions. As #Woohaik has already mentioned, checking for data existence in the useEffect. I'd implement a guard:
useEffect(() => {
if (!data) return
console.log(data.test.test)
}, [data])
or you could make yourself acquainted with optional chaining (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining):
useEffect(() => {
console.log(data?.test?.test)
}, [data])

Missing dependency: 'dispatch' in React

In my react/redux app, i'm using dispatch to call the action that retrieve data from state in redux each time the component is mounted. The problem is happening on useState My way does not work
Below is the error I'm getting:
React Hook useEffect has a missing dependency: 'dispatch'. Either include it or remove the dependency array. Outer scope values like 'getInvoiceData' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
Here is my code:
const TableSection = () => {
const invoiceData = useSelector((state => state.tables.invoiceData));
const dispatch = useDispatch()
useEffect(() => {
dispatch(getInvoiceData());
}, [getInvoiceData]);
(...)
export default TableSection;
You need to add dispatch function to dep array:
const TableSection = () => {
const dispatch = useDispatch()
useEffect(() => {
dispatch(getInvoiceData());
}, [dispatch]);
Its safe to add it to dep array because its identity is stable across renders, see docs.
Note: like in React's useReducer, the returned dispatch function identity is stable and won't change on re-renders (unless you change the store being passed to the , which would be extremely unusual).
This is not an error, its just a warning.
You can fix this by adding dispatch in the dependency array.
useEffect(() => {
dispatch(getInvoiceData());
}, [dispatch]);
second part of the warning message states, Outer scope values like 'getInvoiceData' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps, you also need to remove getInvoiceData function from the dependency array of useEffect hook.
Anything from the scope of the functional component, that participates in react's data flow, that you use inside the callback function of useEffect should be added in the dependency array of the useEffect hook.
Although, in your case, it is safe to omit dispatch function from the dependency array because its guaranteed to never change but still it won't do any harm if you add it as a dependency.

Accessing context from useEffect

I have a context that is used to show a full page spinner while my application is performing long running tasks.
When I attempt to access it inside useEffect I get a the react-hooks/exhaustive-deps ESLint message. For example the following code, although it works as expected, states that busyIndicator is a missing dependency:
const busyIndicator = useContext(GlobalBusyIndicatorContext);
useEffect(() => {
busyIndicator.show('Please wait...');
}, []);
This article suggests that I could wrap the function with useCallback which might look as follows:
const busyIndicator = useContext(GlobalBusyIndicatorContext);
const showBusyIndicator = useCallback(() => busyIndicator.show('Please wait...'), []);
useEffect(() => {
showBusyIndicator();
}, [showBusyIndicator]);
Although this works it has moved the issue to the useCallback line which now complains about the missing dependency.
Is it ok to ignore the ESLint message in this scenario or am I missing the something?
If your busyIndicator is not changed during the life of the component, you could simply add it as a dependency to useEffect:
const busyIndicator = useContext(GlobalBusyIndicatorContext);
useEffect(() => {
busyIndicator.show('Please wait...');
}, [busyIndicator]);
If busyIndicator could be changed and you don't want to see an error, then you could use useRef hook:
const busyIndicator = useRef(useContext(GlobalBusyIndicatorContext));
useEffect(() => {
busyIndicator.current.show('Please wait...');
}, []);
The useRef() Hook isn’t just for DOM refs. The “ref” object is a generic container whose current property is mutable and can hold any value, similar to an instance property on a class. read more
No need to Wrap your useContext in useRef Hook.
you can update your context data just call in useEffect Brackets
like this.
const comingData = useContext(taskData);
useEffect(() => {
console.log("Hi useEffect");
}},[comingData]); //context data is updating here before render the component

Resources