Solid JS路由条件渲染问题:基于登录状态控制路由组件显示
解决SolidJS中基于登录状态的路由条件渲染问题
你的当前写法存在几个核心问题:
- 每个路由重复判断登录状态,代码冗余且易出错
- 直接通过
component属性切换组件,Solid的响应式更新逻辑会导致路由匹配混乱,出现渲染异常 - 缺少合理的重定向逻辑,未登录访问私有路由、已登录访问登录页时的跳转行为不清晰
以下是更规范且可维护的实现方案:
1. 封装私有路由组件
创建一个ProtectedRoute组件,统一处理登录校验和重定向逻辑,避免重复代码:
import { Route, Navigate } from "@solidjs/router"; type ProtectedRouteProps = { children: JSX.Element; user: unknown; // 根据你的user类型调整 loading?: boolean; // 可选,处理异步加载状态 }; export function ProtectedRoute({ children, user, loading }: ProtectedRouteProps) { // 处理异步加载中的状态 if (loading) { return <div>加载中...</div>; // 替换为你的加载组件 } // 未登录时重定向到登录页,携带当前路径用于登录后跳转 if (!user) { return <Navigate href={`/login?redirect=${window.location.pathname}`} />; } return children; }
2. 重构路由结构
将公开路由(未登录可访问)和私有路由(需登录)分开,用嵌套路由整理层级,让结构更清晰:
import { Router, Route, Navigate } from "@solidjs/router"; import { ProtectedRoute } from "./ProtectedRoute"; // 导入你的页面组件:HomeScreen、LoginScreen、InventoryScreen等 export const App = () => { const [authAccount] = useAuth(); const { user, token, loading } = authAccount.auth; return ( <Router> {/* 公开路由:未登录可访问,已登录自动跳首页 */} <Route path="/login"> {!loading && (!user ? <LoginScreen /> : <Navigate href="/" />)} </Route> <Route path="/register"> {!loading && (!user ? <RegistrationScreen /> : <Navigate href="/" />)} </Route> <Route path="/fp"> {!loading && (!user ? <ForgotPasswordScreen /> : <Navigate href="/" />)} </Route> {/* 私有路由:需登录才能访问 */} <Route path="/"> <ProtectedRoute user={user} loading={loading}> <Route path="/" component={HomeScreen} /> {/* 库存相关子路由 */} <Route path="/inventory"> <Route path="/" component={InventoryScreen} /> <Route path="/:itemID" component={ViewItemScreen} /> <Route path="/add" component={AddItemScreen} /> <Route path="/edit/:itemID" component={EditItemScreen} /> </Route> {/* 交易相关子路由 */} <Route path="/transaction"> <Route path="/" component={TransactionScreen} /> <Route path="/:transactionID" component={ViewTransactionScreen} /> <Route path="/edit/:transactionID" component={EditTransactionScreen} /> <Route path="/add/in/:itemID?" component={TransactionInScreen} /> <Route path="/add/out/:itemID?" component={TransactionOutScreen} /> <Route path="/add/lent/:itemID?" component={TransactionLentScreen} /> <Route path="/add/return/:itemID?" component={TransactionReturnScreen} /> </Route> {/* 设置相关子路由 */} <Route path="/settings"> <Route path="/" component={AccountSettingsScreen} /> <Route path="/notifications" component={NotificationSettingsScreen} /> <Route path="/password" component={PasswordSettingsScreen} /> </Route> <Route path="/ran" component={RemindersAndNotificationScreen} /> </ProtectedRoute> </Route> {/* 404 fallback:匹配所有未定义的路径 */} <Route path="*"> <Navigate href="/" /> </Route> </Router> ); };
3. 补充登录后的跳转逻辑
在LoginScreen中,登录成功后可以读取redirect参数,跳回用户原本想要访问的页面:
import { useSearchParams, useNavigate } from "@solidjs/router"; export function LoginScreen() { const searchParams = useSearchParams(); const navigate = useNavigate(); const handleLogin = async () => { // 执行登录逻辑... const redirectUrl = searchParams.redirect || "/"; navigate(redirectUrl); }; return ( // 登录表单... ); }
关键优化点说明
- 代码复用:通过
ProtectedRoute统一处理权限校验,避免每个路由重复写判断逻辑 - 路由清晰:嵌套路由让层级结构更直观,维护起来更方便
- 状态处理:加入加载状态判断,避免在auth数据未加载完成时出现错误跳转
- 用户体验:登录后跳回原路径,提升使用流畅度
内容的提问来源于stack exchange,提问作者Cozy
相关产品推荐
相关产品推荐

