Taken two pages back since render function is called twice

Viewed 33

I want to go back to the previous page when Apollo Client error.graphQLErrors has an error with a specific message from the backend server.

Below is the snippet of my code,

const Detail = () => {
  const { snackbar } = useSnackbar();
  const history = useHistory();
  return (
    <Compo query={graphQLQuery}>
      {({ data, error,  }) => {
        if (error?.graphQLErrors[0]?.extensions?.debugMessage.includes('Specific Error')) {
          history.goBack();
          snackbar('Specific Error');
          return <></>;
        } else {
          //render another component
        }
      }}
    </Compo>
  );

Issue is since the render is called twice, when the error happens, history.goBack() is executed twice and I'm taken two pages back. I'm able to avoid this by removing <React.StrictMode> encapsulating <App> component. Is there a better way to do this? I'm trying to avoid removing <React.StrictMode> since it's been there since a long time.

1 Answers

Issue

The issue here is that you are issuing an unintentional side-effect from the render method. In React function components the entire function body is considered to be the "render" method. Move all side-effects into a useEffect hook.

Solution

Since the code is using a children function prop you'll need to abstract what the "child" is rendering into a React component that can use React hooks.

Example:

const DetailChild = ({ data, error }) => {
  const history = useHistory();
  const { snackbar } = useSnackbar();

  const isErrorCondition = error?.graphQLErrors[0]?.extensions?.debugMessage.includes('Specific Error'

  useEffect(() => {
    if (isErrorCondition)) {
      history.goBack();
      snackbar('Specific Error');
    }
  }, [error]);

  return isErrorCondition
    ? null
    : (
      ... render another component ...
    );
};

...

const Detail = () => {
  return (
    <Compo query={graphQLQuery}>
      {({ data, error }) => <DetailChild {...{ data, error }} />}
    </Compo>
  );
};
Related