Unsure of how to trigger useEffect when updating a nested object property in component state

Viewed 2913

How do I trigger a the useEffect hook when state.providers["providerId"].isProviderRowValid changes?

I cannot put state into the dependency array as it will cause an infinite loop because of the subsequent state update to isSubmitDisabled.

  const providerRowHandler = (providerId: string, isRowValid: boolean): void => {
    setState({
      ...state,
      providers: {
        ...state.providers,
        [providerId]: {
          ...state.providers[providerId],
          isProviderRowValid: isRowValid
        }
      }
    });
  };

  useEffect(() => {
    console.log('state.providers changed, update form state');
    const providers = { ...state.providers };
    const isRowsValid = Object.values(providers)
      .map(k => k.isProviderRowValid)
      .every(row => row === true);
    setState({
      ...state,
      isSubmitDisabled: isRowsValid === false
    });
  }, [// how to watch isProviderRowValid only as a state update here ]);
2 Answers

I think you can run whenever state.providers changed:

useEffect(() => {
  setState((state) => {
    console.log(
      'state.providers changed, update form state'
    );
    const isSubmitDisabled =
      Object.values(state.providers)
        .map((k) => k.isProviderRowValid)
        .every((row) => row === true) === false;
    if (isSubmitDisabled !== state.isSubmitDisabled) {
      //need to change state
      return {
        ...state,
        isSubmitDisabled,
      };
    }
    //do nothing
    return state;
  });
}, [state.providers]);
  function getAllProviderRows() {
    const providers = { ...state.providers };
    return Object.keys(providers).map(item => providers[item].isProviderRowValid);
  }

  useEffect(() => {
    const providers = { ...state.providers };
    const isRowsValid = Object.values(providers)
      .map(v => v.isProviderRowValid)
      .every(row => row === true);
    setState({
      ...state,
      isSubmitDisabled: isRowsValid === false
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [getAllProviderRows]);

I cannot log into my app currently but this should work

Related