Search code examples
javascripturlreact-router-dom

Add a path if the url has error param in react-router-dom


import { Provider } from 'jotai'
import React from 'react'
import ReactDOM from 'react-dom/client'
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
import App from './App.tsx'
import Auth from './Auth.tsx'
import NewPass from './NewPass.tsx'
import ResetPassword from './ResetPassEmail.tsx'
import './index.css'

const router = createBrowserRouter([
  {
    path: "/",
    element: <Auth />,
  },
  {
    path: "/chatroom",
    element: <App />,
  },
  {
    path: "/psdResetEmail",
    element: <ResetPassword />,
  },
  {
    path: "/psdReset/:access_token=:access_token&token_type=:token_type&type=:type",
    element: <NewPass />,
  },
  {
    path: "/psdReset/:error=:error&error_code=:error_code&error_description=:error_description",
    element: <Auth />,
  },
]);

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <Provider>
      <RouterProvider router={router} />
    </Provider>
  </React.StrictMode>
);

I am currently using this method to create routers, but I am getting errors when I am trying to create new paths for access_token and error but getting back 404 error.

The error URL looks like this: "http://localhost:5173/psdReset#error=unauthorized_client&error_code=401&error_description=Email+link+is+invalid+or+has+expired"

The access_token URL looks the same but with access_token params.

I am trying to use the URL hash.


Solution

  • The Route component's path prop only uses the URL path part for route matching, adding the hash/queryString won't work and actually breaks route matching.

    I suggest creating a single component that can read the hash/queryString and conditionally render the routed component or issue a back navigation if there isn't a "match".

    Example:

    const PasswordReset = () => {
      const navigate = useNavigate();
      const { hash } = useLocation();
      
      // Create a URLSearchParams object from the hash value
      const searchParams = React.useMemo(() => new URLSearchParams(hash), [hash]);
    
      // Unpack any token values
      const accessToken = searchParams.get("access_token");
      const tokenType = searchParams.get("token_type");
    
      // Unpack any error values
      const error = searchParams.get("error");
      const errorCode = searchParams.get("error_code");
      const errorDescription = searchParams.get("error_description");
    
      // Compute which component type you want to render
      const isNewPass = accessToken && tokenType;
      const isAuth = error && errorCode && errorDescription;
    
      useEffect(() => {
        // If no "match" then navigate back
        if (!(isNewPass || isAuth)) {
          navigate(-1);
        }
      }, [isNewPass, isAuth, navigate]);
    
      // Render appropriate "match"
      if (isNewPass) {
        return <NewPass />;
      } else if (isAuth) {
        return <Auth />;
      }
    
      // No "match" render null
      return null;
    };
    
    const router = createBrowserRouter([
      {
        path: "/",
        element: <Auth />,
      },
      {
        path: "/chatroom",
        element: <App />,
      },
      {
        path: "/psdResetEmail",
        element: <ResetPassword />,
      },
      {
        path: "/psdReset",
        element: <PasswordReset />,
      },
    ]);