6

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?

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the fast response This is correct, but I still got the issue with the prop 'setIsValid' since he still demands this as a dependency. Any Ideas how I could go around this?
Updated my answer
You could also add props.setIsValid as a dependency directly without destructuring.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.