如何根据登录用户的类型更改浏览器路由器

问题描述 投票:0回答:2

我正在使用 Meteor.js 和 React 构建一个 Web 应用程序。该应用程序有两种类型的用户:“用户”和“雇主”,每种用户都有自己的路线(如不同的仪表板和其他页面)。所以我有一个

UserRouter
、一个
EmployerRouter
和一个
UnprotectedRouter
(当用户尚未登录时)。我想根据登录的用户返回不同的路由器(我有一个“类型”字段让我知道他们是什么用户类型)。问题是当用户登录时路由器不会更新。基本上我需要不同的路由器,不仅取决于用户是否登录,还取决于用户的类型。

我尝试使用

useState
,但它不会更新路由器。然后我想,因为浏览器在用户注册后重新路由,也许它会重新运行
App.tsx
,这会将路由器更新为正确的路由器,但这也不起作用。现在,当我启动应用程序时,它会呈现
UnprotectedRouter
,因为我尚未登录。然后,当我转到注册表单并创建一个新用户(自动登录)时,它仍然显示
 UnprotectedRouter
而不是
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>
  );
};

雇主路由器.tsx

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

未受保护的路由器.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>
  );
};

应用程序.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>
  )
};

这就是我的用户注册方法:

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);
};
reactjs typescript meteor react-router meteor-accounts
2个回答
0
投票

我渲染的内容在 App.tsx 上,你需要包装

const router = RouterChoice();

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

像这样:

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

对于我使用的依赖项<>,但是当用户使用不同的帐户登录时,您应该使用哪些更改。


0
投票

问题似乎是你错误地设置了

RouterChoice
函数名称,它“欺骗”React,或者更确切地说“钩子规则”,让其认为
RouterChoice
是一个 React 组件而不是常规回调函数。
RouterChoice
调用
useSubscribe
React 钩子,但因为
App
没有被触发重新渲染,所以它不会再次调用
useSubscribe
,因为
RouterChoice
永远不会再次作为 React 组件“被调用”。

RouterChoice
重命名为
useRouterChoice
之类的名称,以便将其作为自定义 React 钩子有效调用。

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>
  );
};

您现在可能遇到的问题是,当身份验证状态/条件发生变化时,UI 和其他路由可能尚未安装和导航。为此,最好无条件渲染所有路线并保护/守卫对路线的访问。

这是使用布局路由的常见路由保护实现。

const ProtectedRoute = ({ type }: { type: "user" | "employer"}) => {
  const isLoadingProfiles = useSubscribe("allUserProfiles");

  const loggedInUsername = Meteor.user()?.username;
  const userType = UserCollection.findOne({ username: loggedInUsername })?.type;

  if (isLoadingProfiles) {
    return null; // or loading indicator/spinner/etc
  }

  return userType === type
    ? <Outlet />
    : <Navigate to="/login" replace />;
};
export const App = () => {
  const router = useRouterChoice();

  return (
    <BrowserRouter>
      <div>
        <Routes>
          {/* unprotected routes */}

          <Route element={<ProtectedRoute type="user" />}>
            {/* protected user routes */}
          </Route>
          <Route element={<ProtectedRoute type="employer" />}>
            {/* protected employer routes */}
          </Route>
        </Routes>
      </div>
    </BrowserRouter>
  );
};

如果您希望经过身份验证的用户无法访问“未受保护”的路由,则可以使用另一个布局路由组件来保护它们,该组件应用

ProtectedRoute
组件的逆逻辑。

const AnonymousRoute = () => {
  const isLoadingProfiles = useSubscribe("allUserProfiles");

  const loggedInUsername = Meteor.user()?.username;
  const userType = UserCollection.findOne({ username: loggedInUsername })?.type;

  if (isLoadingProfiles) {
    return null; // or loading indicator/spinner/etc
  }

  return !!userType
    ? <Navigate to={/* any safe authenticated/protected route path */} replace />
    : <Outlet />;
};
export const App = () => {
  const router = useRouterChoice();

  return (
    <BrowserRouter>
      <div>
        <Routes>
          <Route element={<AnonymousRoute />}>
            {/* unprotected routes */}
          </Route>
          <Route element={<ProtectedRoute type="user" />}>
            {/* protected user routes */}
          </Route>
          <Route element={<ProtectedRoute type="employer" />}>
            {/* protected employer routes */}
          </Route>
        </Routes>
      </div>
    </BrowserRouter>
  );
};
© www.soinside.com 2019 - 2024. All rights reserved.