skip to Main Content

I am using Suspense from React, and Await from React-Router-DOM to wait for a promise and return JSX on resolve, but in most cases I want to call some functions like navigate or something else, then the functions are called twice. I want to prevent that.

Loader

export const Loader = async ({ params }) => {
  CheckAuth();
  let fetch_data = fetchApi('auth/activate-account', 'POST', { verify_token: params.verify_token });
  return defer({ loaderPromise: fetch_data });
}
// this loader is called in the Route loader prop
const VerifyToken = () => {            
  const loaderData = useLoaderData();
            
  const navigate = useNavigate();
            
  const { showAlert } = useGeneral();
            
  return (
    <React.Suspense fallback={<PreLoader />}>
      <Await resolve={loaderData.loaderPromise}>
        {(resolvedData) => {
          if (resolvedData.type === "warning") {
            showAlert(resolvedData.type, resolvedData.msg);
            navigate('/Auth/Login', { replace: true });
            return null;
          }
          return (
            { JSX }
          );
        }}
      </Await>
    </React.Suspense>
  );
};

This causes calling the navigate and showAlert functions twice. I want to prevent that or use another approach or other methods.

I tried this:

let loaderRef = React.useRef(false);
    
<React.Suspense fallback={<PreLoader />}>
  <Await resolve={loaderData.loaderPromise}>
    {(resolvedData) => {
      if (!loaderRef.current) {
        showAlert(resolvedData.type, resolvedData.msg);
        loaderRef.current = true;
        setTimeout(() => {
          navigate('/Auth/Login', { replace: true });
        }, 0);
        return null;
      }
    }}
  </Await>
</React.Suspense>

This works but not efficient in most cases.

2

Answers


  1. I don’t have a full picture to help you, but I’ll try to guest
    Are you using react in StrictMode in development?
    It will make React rerender twice every component trying to avoid errors

    If is not the case, please provide a way to test the application

    https://react.dev/reference/react/StrictMode#strictmode

    Strict Mode enables the following development-only behaviors:

    Your components will re-render an extra time to find bugs caused by impure rendering.
    Your components will re-run Effects an extra time to find bugs caused by missing Effect cleanup.
    Your components will be checked for usage of deprecated APIs.

    Login or Signup to reply.
  2. I suspect there is some rendering issue being exposed by a React.StrictMode component higher up the ReactTree, specific lifecycle functions are double-invoked in non-production builds to expose logical issues in your code like unintentional side-effects.

    Abstract the unintentional side-effect of showing the alert and navigating into a React component that can use the useEffect hook to correctly issue an intentional side-effect to show the alert and conditionally redirect or render the specified JSX content.

    Example:

    const DataHandler = ({ children, resolvedData }) => {
      const { showAlert } = useGeneral();
    
      useEffect(() => {
        if (resolvedData.type === "warning") {
          showAlert(resolvedData.type, resolvedData.msg);
        }
      }, [resolvedData]);
    
      if (resolvedData.type === "warning") {
        return <Navigate to='/Auth/Login' replace />;
      }
    
      return children;
    };
    
    const VerifyToken = () => {        
      const loaderData = useLoaderData();
      
      return (
        <React.Suspense fallback={<PreLoader />}>
          <Await resolve={loaderData.loaderPromise}>
            {(resolvedData) => {
              return (
                <DataHandler resolvedData={resolvedData}>
                  { JSX }
                </DataHandler>
              );
            }}
          </Await>
        </React.Suspense>
      );
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search