2

I am currently generating the useEffect has a missing dependency warning and I'm having a tough time understanding how to change the logic so that it is idiomatic and "correct".

To start, I have an HOC that displays an alert dialog. This HOC provides a prop to the wrapped component to display this alert dialog with a message. Here's the HOC:

function withAlertDialog(WrappedComponent) {
  return function(props) {
    const [dialogOps, setDialogOps] = useState({open: false, message: "", // additional properties});

    const closeDialog = () => {
      setDialogOps({...dialogOps, open: false});
    }

    const openDialog = message => {
      setDialogOps({...dialogOps, open: true, message});
    }

    return (
      <React.Fragment>
        <WrappedComponent 
          {...props}
          onOpen={openDialog}
          onClose={closeDialog} />
        <MyDialogComponent
          open={dialogOps.open}
          message={dialogOps.message} />
      </React.Fragment>
    )
  }
}

The reason I use this HOC is so that wrapped components have an easy way of displaying a dialog without having to worry about managing its state. This really helps when there are several components that need to display a basic alert dialog, a lot of code is slimmed down.

Now I'm trying to use this in a component. The idea is that once a user has been retrieved, I'd like to make an api call to retrieve some data for this user. The effect should only run when a the user has changed, and the api call should only run once. Additionally, this user is coming from redux. Here's the component:

function MyComponent(props) {
  const user = useSelector(state => state.user); // New use selector hook from react-redux
  const {onOpen} = props;

  useEffect(() => {
    async function retrieveDataAsync() {
      let client = new MyClient(); // Some generic client
      try {
        let response = await client.getAsync(); // Some generate data retrieval function
        console.log(response.data);
      } catch (error) {
        onOpen(error.errorMessage);
      }
    }

  if (user) retrieveDataAsync();
  }, [user]);
}

export default withAlertDialog(MyComponent);

Now I get the error message in the console that the dependency onOpen is missing. How exactly do I restructure this to be "correct" in the new react hooks way?

I don't want to add onOpen as a dependency because MyComponent gets re-rendered several times by a parent component for other reasons, this means that onOpen will always be different from previous, which means my api call that should only happen once, is now executed every time MyComponent is re-rendered.

I tried to use useCallback on the onOpen function:

const openDialog = useCallback(message => {
  setDialogOps({...dialogOps, open: true, message});
}, [dialogOps]);

The problem now is that whenever dialogOps changes, this triggers the useEffect to run again, because the function has changed.

I am now stuck and not sure how to resolve this.

Stalfos
  • 1,348
  • 2
  • 9
  • 12
  • When you are absolutely sure, that you don't need the deps parameter, you need not worry about the warning and disable it. The warning is there to warn you against unintended issues – Shubham Khatri May 31 '19 at 05:47

0 Answers0