Inside of my useEffect, I have a props dependency (setIsValid). When I add this dependency to the useEffect, it lands in an infinite loop.
Parent when Calling Child Component:
const setIsValid = (bool) => {
const tmpStateCopy = Object.assign({}, state);
tmpStateCopy.isValid = bool;
setState(tmpStateCopy);
};
return <Child
setIsValid={setIsValid}
/>
In the Child Component:
const { setIsValid } = props;
const [state, setState] = useState({
transformations: [],
duplicateIndexes: []
});
const { transformations, duplicateIndexes } = state;
useEffect(() => {
const invalids = transformations.find(x => (x.value === '' || x.replaceWith === ''));
const hasDuplicates = duplicateIndexes.length > 0;
const isValid = ((invalids === undefined) && (transformations.length > 0) && !hasDuplicates);
setIsValid(isValid)
console.log('got triggered');
}, [state]);
This way the code works but I always get a warning.
What I want is, that the validation is always triggered when one of the values inside the state changes (transformations / duplicateIndexes).
By adding the setIsValid() func from the props, it runs infinitely.
The Warning looks like this:
./src/components/UI/integrationBuilder/layoutElements/transformer/modules/ifModules/ifModule.js
Line 103: React Hook useEffect has missing dependencies: 'duplicateIndexes.length', 'setIsValid', and 'transformations'. Either include them or remove the dependency array react-hooks/exhaustive-deps
My question is, how can I keep the same logic without getting this warning?
To get rid of your infinite loop, simply use an empty dependency array like so: const [count, setCount] = useState(0); //only update the value of 'count' when component is first mounted useEffect(() => { setCount((count) => count + 1); }, []); This will tell React to run useEffect on the first render.
By executing a function before setting a handler, you update a state inside the render, which causes an infinite loop.
Changing state will always cause a re-render. By default, useEffect always runs after render has run. This means if you don't include a dependency array when using useEffect to fetch data, and use useState to display it, you will always trigger another render after useEffect runs.
useEffect(() => setCount(count + 1)); it generates an infinite loop of component re-renderings.
Since, when state changes you will call the effect. transformations and duplicateIndexes will already be considered for. To avoid the warning, you can move the destructure
within useEffect
const { setIsValid } = props;
const [state, setState] = useState({
transformations: [],
duplicateIndexes: []
});
useEffect(() => {
const { transformations, duplicateIndexes } = state;
const invalids = transformations.find(x => (x.value === '' || x.replaceWith === ''));
const hasDuplicates = duplicateIndexes.length > 0;
const isValid = ((invalids === undefined) && (transformations.length > 0) && !hasDuplicates);
setIsValid(isValid)
console.log('got triggered');
}, [state]);
Also regarding setIsValid as a dependency to useEffect, you must not do that since a new function for it is created on every render and it will cause the useEffect to to run again and again unles you refactor your code a bit.
const setIsValid = useCallback((bool) => {
setState(prev => Object.assign({}, prev, {isValid: bool});
}, []);
and now you can set setIsValid
as a dependency.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With