skip to Main Content

I am building a web app using Meteor.js with React. The app has two types of users: "user" and "employer", each with their own routes (like different dashboards and other pages). So I have a UserRouter, an EmployerRouter, and an UnprotectedRouter (for when the user is not logged in yet). I want to return a different router depending on which user is logged in (I have a "type" field to let me know which user type they are). The issue is that the router is not updating when a user logs in. Basically I need different routers depending not only on if the user is logged in or not, but what TYPE of user it is.

I tried to do useState, but it wouldn’t update the router. Then I thought because the browser reroutes after the user signs up, maybe it would rerun App.tsx which would update the router to the correct one, but that did not work either. Right now when I start up the app, it renders the UnprotectedRouter because I’m not logged in. Then when I go to the sign-up form and create a new user (which logs me in automatically), it still shows UnprotectedRouter rather than UserRouter.

This is what my code currently looks like:

UserRouter.tsx

export const UserRouter = () => {
  return (
    <Routes>
      <Route path={RoutePaths.USER_HOME} element={<UserHome />} />
      <Route path={RoutePaths.USER_PROFILE} element={<UserProfile />} />
      <Route path={RoutePaths.EMPLOYER_HOME} element={<EmployerHome />} />
      <Route path={RoutePaths.USER_SIGNUP} element={<UserSignUp />} />
      <Route path={RoutePaths.EMPLOYER_SIGNUP} element={<EmployerSignUp />} />
      <Route path={RoutePaths.USER_SIGNIN} element={<UserSignIn />} />
      <Route path="/position/:postingId" element={<UserPosting />}/>
    </Routes>
  );
};

EmployerRouter.tsx

export const EmployerRouter = () => {
    return (
      <Routes>
        <Route path={RoutePaths.USER_HOME} element={<EmployerDashboard />} />
      </Routes>
    );
  };

UnprotectedRouter.tsx

export const UnprotectedRouter = () => {
  return (
    <Routes>
      <Route path={RoutePaths.WELCOME_PAGE} element={<WelcomePage />} />
      <Route path={RoutePaths.USER_SIGNUP} element={<UserSignUp />} />
      <Route path={RoutePaths.EMPLOYER_SIGNUP} element={<EmployerSignUp />} />
    </Routes>
  );
};

App.tsx

const selectRouter = (userType: String) => {
  switch (userType) {
      case "user":
          return <UserRouter/>
      case "employer":
          return <EmployerRouter/>
      default:
          return <UnprotectedRouter/>
  }
}

const RouterChoice = () => {
  const isLoadingProfiles = useSubscribe("allUserProfiles");
  const loggedInUsername = Meteor.user()?.username;
  const userType = UserCollection.findOne({ username: loggedInUsername })?.type;

  return selectRouter(userType)
}


export const App = () => {
  const router = RouterChoice();

    return (
      <BrowserRouter>
        <div>
          {router}
        </div>
      </BrowserRouter>
    )

};

This is what my sign-up method for users looks like:

  const handleSignUp = (e: { preventDefault: () => void }) => {
    e.preventDefault();
    console.log("password is: " + password);
    console.log("username is: " + username);
    console.log("email is: " + email);
    Accounts.createUser(
      {
        username: username,
        password: password,
        email: email,
      },
      (error) => {
        if (error) {
          console.log(error);
          return;
        } else {
          console.log("success!");
        }
      }
    );

    Meteor.call("user-profile.createNewProfile", {
      username: username,
      name: name,
      type: "user",
    });

    setName("");
    setUsername("");
    setEmail("");
    setPassword("");
    console.log("submitted!");
    navigate(RoutePaths.USER_HOME);
  };

Thank you for your help.

2

Answers


  1. What I have rendered is on App.tsx you need to wrap

    const router = RouterChoice();
    

    By a

    useEffect(() => {}, [])
    

    Like this:

    useEffect(() => {
        const router = RouterChoice();
    }, [Meteor.user()?.username])
    

    For the dependency I used <<Meteor.user()?.username>> but you should use what changes when the user logs in with a different account.

    Login or Signup to reply.
  2. The issue it seems is that you have incorrectly cased the RouterChoice function name which "tricks" React, or rather "Rules of Hooks", into thinking that RouterChoice is a React component instead of a regular callback function. RouterChoice calls a useSubscribe React hook, but because App isn’t triggered to rerender it doesn’t call the useSubscribe again because RouterChoice is never "called" again as a React component.

    Rename RouterChoice to something like useRouterChoice so it’s called validly as a custom React hook.

    const selectRouter = (userType: String) => {
      switch (userType) {
        case "user":
          return <UserRouter />;
        case "employer":
          return <EmployerRouter />;
        default:
          return <UnprotectedRouter />;
      }
    };
    
    const useRouterChoice = () => {
      const isLoadingProfiles = useSubscribe("allUserProfiles");
      const loggedInUsername = Meteor.user()?.username;
      const userType = UserCollection.findOne({ username: loggedInUsername })?.type;
    
      return selectRouter(userType);
    };
    
    export const App = () => {
      const router = useRouterChoice();
    
      return (
        <BrowserRouter>
          <div>
            {router}
          </div>
        </BrowserRouter>
      );
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search