Home > Net >  Problem with checking Conditions in useEffect and React Router v6
Problem with checking Conditions in useEffect and React Router v6

Time:07-29

Thank you for reading through my Issue and for your effort, to help me and give me guidance to my problem

I have this Problem. I'm using React Router Version 6. I a added ProtectedRoutes for logged in Users. Thats all working. But in some views I check for example, if the user has an active subscription, and if not, i redirect him to a CreateSubscription Page. I do this check on an model, which I got from an Context.

Problem is, that the View gets rendered, and shortly after that redirects to the correct view (fetch on render). Can I somewhat check before render and then decide what to show ? Does the React Suspense API can manage such conditionals ? Actually I do the check like this.

  const { workshop, token } = useWorkshopContext();

  useEffect(() => {
    if (!workshop) {
      return;
    }
    //TODO: Get Redirects clustered to own Service and move to a hook before mounting to remove the show old view bevore routing. this is ugly!!!!
    if (workshop?.status === WORKSHOP_OLD_EXISTING_CUSTOMER) {
      navigate('/account/welcome');
    } else {
      if (workshop?.status !== WORKSHOP_ACTIVE) {
        navigate('/setup/subscription');
      }
    }
  }, [workshop]);

and on the Create Subscription Page I use This.

 useEffect(() => {
    if (!workshop) {
      return;
    }
    if (workshop?.status === WORKSHOP_OLD_EXISTING_CUSTOMER) {
      navigate('/account/welcome');
    }

    if (workshop?.status === WORKSHOP_ACTIVE) {
      navigate('/app/dashboard');
    }
  }, [workshop]);

Routesfile looks like kinda:

   <SentryRoutes location={location} key={location.pathname}>
            <Route index element={<LandingPage />} />
            <Route path="/" element={<LandingPage />} />
            <Route path="/login" element={<RedirectToAuth0Login />} />
            <Route path="/signup" element={<RegistrationPage />} />
            <Route
              path="/signup/:workshop_id/:registration_form_key"
              element={<RegistrationPage />}
            />
            <Route path="setup" element={<LandingPage />} />
            <Route
              path="setup"
              element={<ProtectedRoute component={PlainLoggedInUserWrapper} />}
            >
              <Route
                path="subscription"
                element={<ProtectedRoute component={CreateSubscriptionPlanPage} />}
              />
              <Route
                path="verification"
                element={<ProtectedRoute component={VerificationPage} />}
              />
              <Route
                path="polling"
                element={<ProtectedRoute component={PollingPage} />}
              />
            </Route>

            <Route
              path={'account'}
              element={<ProtectedRoute component={WorkshopContextView} />}
            >
              <Route
                path="welcome"
                element={<ProtectedRoute component={WelcomeExistingCustomerPage} />}
              />
            </Route>

            <Route
              path="app"
              element={<ProtectedRoute component={LoggedInUserAppShell} />}
            >
              <Route index element={<ProtectedRoute component={Dashboard} />} />
              <Route path="profile" element={<ProtectedRoute component={Profile} />} />
              <Route
                path="account/verification"
                element={<ProtectedRoute component={AccountVerificationPage} />}
              />
              <Route
                path="account/update"
                element={<ProtectedRoute component={AccountUpdateDataPage} />}
              />
              <Route
                path="account/subscription"
                element={<ProtectedRoute component={ManageSubscriptionPage} />}
              />
              <Route
                path="vehicle"
                element={<ProtectedRoute component={VehicleIdentificationPage} />}
              />
              <Route
                path="service-record/create"
                element={<ProtectedRoute component={CreateServiceRecordPage} />}
              />
              <Route
                path="service-record/:id/update"
                element={<ProtectedRoute component={UpdateServiceRecordPage} />}
              />
              <Route
                path="service-record/:id"
                element={<ProtectedRoute component={ServiceRecordDetailsPage} />}
              />
              <Route
                path="request-service-record-history"
                element={<ProtectedRoute component={ServiceHistoryPage} />}
              />
              <Route
                path="request-service-record-history/:id"
                element={<ProtectedRoute component={ServiceHistoryPage} />}
              />
              <Route
                path="request-inspection-plan"
                element={<ProtectedRoute component={InspectionPlanPage} />}
              />
              <Route
                path="service-activities"
                element={<ProtectedRoute component={ActivitiesOverview} />}
              />
              <Route
                path="dashboard"
                element={<ProtectedRoute component={Dashboard} />}
              />
            </Route>
            <Route path="error" element={<ErrorPage />} />
            <Route path="404" element={<Page404 />} />
            <Route path="*" element={<Page404 />} />
          </SentryRoutes>

It uses an different layout, than the upper View, so I couldn't to a conditional branching in the Layout component

In Vue router, they had the concept of before view render guards, which didn't work here in react router. I tried to wrap it in descision wrapper components, I tried with passing callbacks (ended in errors with using useState in useEffect :)), somewhat tried with xstate, tried react-location, but everything failed. Does someone already solved this puzzle ? I'm pretty sure, because I think thats an quite common use case, but i failed on research. Thanks in advance regards Rainer

CodePudding user response:

Does this works for you ?

import { Navigate } from 'react-router-dom'

//...

function SomeComponent() {
  const { workshop, token } = useWorkshopContext()

  if (!workshop || !workshop.status) return <div>Loading...</div>

  if (workshop.status === WORKSHOP_OLD_EXISTING_CUSTOMER) return <Navigate to="/account/welcome" />

  if (workshop.status !== WORKSHOP_ACTIVE) return <Navigate to="/setup/subscription" />

  return <div>Hello world</div>
}

useEffect verison

import { Navigate } from 'react-router-dom'

const { workshop, token } = useWorkshopContext()

function SomeComponent2() {
  const { workshop, token } = useWorkshopContext()

  useEffect(() => {
    if (!workshop || !workshop.status) {
      return
    }

    if (workshop.status === WORKSHOP_OLD_EXISTING_CUSTOMER) {
      navigate('/account/welcome')
    } else {
      if (workshop.status !== WORKSHOP_ACTIVE) {
        navigate('/setup/subscription')
      }
    }
  }, [workshop])

  if (!workshop || !workshop.status) return <div>Loading...</div>

  return <div>Hello world</div>
}

CodePudding user response:

Maybe you can use the useInsertionEffect() hook for this. Although the react team suggests this to use for the library authors but this can be of use here.

The useInsertionEffect() hook is fired before the DOM mutations are made.

Read more about it here:

Note: This hook is only available since React 18.

  • Related