Missing dependency: 'dispatch' in React - reactjs

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.

Related

Use set function from custom hooks inside useEffect

I created a custom hook that maintain state in a certain type based on data in a different type like this:
import { useState, useRef, Dispatch } from 'react';
function useBackedState<TData, TBacking>(initialData: TBacking, converter: (backing: TBacking) => TData):
[
state: TData,
getBackingData: () => TBacking,
setData: Dispatch<TBacking>
] {
const ref = useRef(initialData);
const [state, setState] = useState(converter(initialData));
const setData: Dispatch<TBacking> = (val: TBacking) => {
ref.current = val;
setState(converter(val));
};
return [
state,
() => ref.current,
setData
];
}
export default useBackedState;
However, I have problems when I call on setData inside a useEffect hook.
For example, I tested it in this component:
import { useState } from 'react';
import useBackedState from './hooks/useBackedState';
function Component() {
const [data, backing, setData] = useBackedState<string, string[]>(
[],
(arr) => arr.join('');
);
const [somethingElse, setSomethingElse] = useState('a');
useEffect(() => {
setSomethingElse('b');
setData(['h', 'e', 'l', 'l', 'o']);
}, []);
return (
<div>
<p>{data}</p>
... some more rendering
</div>
);
}
I want useEffect to only run once at the start, so I provided an empty array of dependencies. However, although the app works, I get this warning:
React Hook useEffect has a missing dependency: 'setData'. Either
include it or remove the dependency array
If I do add setData as a dependency, the entire app goes into an infinite loop of refresh and I get this error:
Warning: Can't perform a React state update on an unmounted component.
This is a no-op, but it indicates a memory leak in your application.
To fix, cancel all subscriptions and asynchronous tasks in a useEffect
cleanup function.
I am not required to add the setSomethingElse as a dependency to useEffect. Why am I required to add setData?
All state and prop values that get referenced inside a hook should have that value in the dependency array - so the argument goes. If you agree and wish to satisfy the linter, here, it's easy - just memoize the functions returned from the custom hook (which is often a good practice anyway, especially when exhaustive-deps is being used).
const setData: Dispatch<TBacking> = useCallback((val: TBacking) => {
ref.current = val;
setState(converter(val));
}, [setState, converter]);
I am not required to add the setSomethingElse as a dependency to useEffect
The linter can see that setSomethingElse comes directly from a state setter function declared in the same component, and thus definitely won't ever change, and so doesn't need to be in the dependency array.

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 do you fix 'React Hook useEffect has a missing dependency:' warnings?

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.

setState in React's useEffect dependency array

What's the idea behind defining the setState values inside useEffect's dependency array?
const [someState, setSomeState] = useState();
...
useEffect(() => {
// Do something
setSomeState('some value');
}, [setSomeState]);
React Hook useEffect has a missing dependency: 'setSomeState'.
Either include it or remove the dependency array.
eslint(react-hooks/exhaustive-deps)
Not exactly sure if this example would cause eslint to ask to define setSomeState in the dependency array, but I have seen this kind of moments when writing with useEffect. What is React listening to in this case? My understanding is that useEffect listens for changes in the values in the dependency array, but would setSomeState ever change? What am I missing here?
In this case, no, the useState setter function will never change, but useEffect doesn't know it is a function from another hook, it just sees a function.
Consider this use case:
const MyComponent = ({ onUpdate }) => {
const [state, setState] = useState();
useEffect(() => {
// state updated, call onUpdate callback with state
onUpdate(state);
}, [onUpdate, state]);
return ...
}
Now parent component can, given
<MyComponent onUpdate={onUpdateHandler} />
define onUpdateHandler as
let onUpdateHandler = console.log;
then later change it while still mounted
onUpdateHandler = state => dispatch({ type: 'SAVE_STATE', state });
By placing the callback in the dependency array the effect hook see the value of onUpdate changed and trigger the effect again. If it didn't include the callback then it would continue to console.log state updates instead of now handling it differently.
It is more likely for values to change than it is for functions to change, but function values can change. You likely have an eslinter that is recommending you add all the variables used within the hook to the dependency array, and this will in most cases be the correct thing to do. A few exceptions are for example, when you want an effect to compute ONLY when the component mounts by specifying an empty array, or not including some variables that are functions that you KNOW will never change during the life of the component, and in these cases you can use the eslint-disable-next-line react-hooks/exhaustive-deps override to unflag it as a warning. Caution though, as this will disable the linting checks so it is possible for bugs to creep in if not paying attention.

Passing in Redux Actions into useEffect's dependencies

I have the predicament of passing in Redux actions into useEffect's dependencies list.
For example,
import { someReduxAction } from '../actions/greatestPathEverMade'
const mapDispatchToProps = () => ({
someReduxAction
})
const DummyComponent = ({ someReduxAction }) => {
useEffect(() => {
someReduxAction()
}, [someReduxAction])
return ( .... )
}
I'm 75% sure that the Redux Action is not changing so I can omit it from useEffect's dependency array but my question is mainly: Is it possible for Redux actions to change? Usually, they are constant in that a basic redux action will dispatch a type and payload object.
The ESLint exhaustive-deps rule has no way to know whether that function will change to a different reference or not, so it will always tell you that the function needs to be added to the dependencies list. The only exceptions are built-in React functions like a useState setter or useReducer dispatch, which React ensures are stable references, and are hardcoded that way into the ESLint rule.

Resources