我正在构建一个React应用,但我无法使路由正常工作。
对于一些Auth路由(/login
,sign-up
,forgot-password
等,我需要一种通用的布局(页眉,页脚)
对于应用程序的其余受保护部分(Home
,Dashboard
等),我需要另一种通用布局
我需要另一个没有任何布局的404页面。
我从这些链接中尝试了几种技术:
但是可以达到工作版本。
这是我目前拥有的:
(注意:目前,我忽略了将未登录的用户阻止到AppLayout的私有路由中的需要,我会在稍后处理)
const App: React.FC = () => {
const history = createBrowserHistory();
return (
<div className="App">
<Router history={history}>
<Switch>
<AppLayout>
<Route path="/home" component={HomePage}/>
<Route path="/dashboard" component={DashboardPage}/>
...
</AppLayout>
<AuthLayout>
<Route path="/login" component={LoginPage}/>
<Route path="/sign-up" component={SignUpPage}/>
...
</AuthLayout>
<Route path="*" component={NotFoundPage} />
</Switch>
</Router>
</div>
);
};
export default App;
AuthLayout
和AppLayout
都很简单并且与此相似(只是每个页眉/页脚都不同):
class AppLayout extends Component {
render() {
return (
<div className="AppLayout">
<header>...</header>
{this.props.children}
<footer>...</footer>
</div>
);
}
}
export default AppLayout;
问题是仅呈现来自AppLayout的路由。
其他路线仅显示AppLayout header
和footer
,但没有任何内容。
这些是我正在使用的React版本:
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0",
任何帮助将不胜感激。
谢谢。
答案 0 :(得分:2)
我花了一些时间找到自己喜欢的答案。 @ johnny-peter和@ gaurab-kc解决方案都很棒,它们使我对React的路由机制更加了解。
@ johnny-peter的解决方案具有迫使我在auth
下(例如/auth/...
和/auth/login
)下为所有auth/sign-up
相关路由添加前缀的缺点。不想。
@ gaurab-kc解决方案仅支持一组路由..因此,如果用户已经注册,则他将无法再访问/login
路由。
直到最近,我仍使用自己的解决方案,该解决方案的问题是“破坏了通用页眉和页脚的全部目的”。正如@ johnny-peter所提到的,它被否决了几次。
现在我正在使用另一种解决方案:
<Router history={browserHistory}>
<Switch>
<Redirect exact from="/" to="/home"/>
<Route exact path={["/login", "/sign-up", ...]}>
<AuthLayout>
<Switch>
<Route
path="/login"
component={LoginPage}
/>
<Route
path="/sign-up"
component={SignUpPage}
/>
</Switch>
</AuthLayout>
</Route>
<Route exact path={[
"/home",
"/dashboard",
...
]}>
<SiteLayout>
<Switch>
<Route
path="/home"
component={HomePage}
/>
<Route
path="/dashboard"
component={DashboardPage}
/>
</Switch>
</SiteLayout>
</Route>
<Route path="*" component={NotFoundPage}/>
</Switch>
</Router>
可防止上述所有缺陷。它允许我执行以下操作:
/login
或其他auth
路由。此解决方案的唯一缺点是拥有更多代码并复制了路由,但这是我愿意支付的费用。
答案 1 :(得分:0)
您可以尝试使用两个不同的switch语句来处理您的Auth和Protected路由。我在工作时有一个类似的用例,而对我来说,有两组开关块只能一次运行。
const App: React.FC = () => {
const history = createBrowserHistory();
return (
<div className="App">
<Router history={history}>
{isLoggedIn ? <PrivateRoutes /> : <AuthRoutes />}
</Router>
</div>
);
};
const PrivateRoutes: React.FC = () => {
return (
<>
<Header />
<Switch>
<Route path="/home" component={HomePage} />
<Route path="/dashboard" component={DashboardPage} />
<Route path="*" component={NotFoundPage} />
</Switch>
<Footer />
</>
);
};
const AuthRoutes: React.FC = () => {
return (
<>
<Header />
<Switch>
<Route path="/login" component={LoginPage} />
<Route path="/sign-up" component={SignUpPage} />
<Route path="*" component={NotFoundPage} />
</Switch>
<Footer />
</>
);
};
答案 2 :(得分:0)
每个布局都应具有一个路径组件,以区别于其他布局。
例如
Auth布局可以位于/auth
下,例如,登录名将为/auth/login
,注册名将为/auth/signup
应用布局可能会位于/app
下,例如,仪表板将为/app/dashboard
,主页将为/app/home
import { Switch, BrowserRouter, Route, Redirect } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Layouts />
</BrowserRouter>
);
}
const NotFound = () => <h1>Not Found</h1>;
function Layouts() {
return (
<Switch>
<Route path="/auth" component={AuthLayout} />
<Route path="/app" component={AppLayout} />
<Route path="/" component={NotFound} />
</Switch>
);
}
const Signup = () => <p>Login</p>;
const Login = () => <p>Sign up</p>;
function AuthLayout() {
return (
<div>
<h1>Auth Layout</h1>
<Route path="/auth/signup" exact component={Signup} />
<Route path="/auth/login" exact component={Login} />
<Redirect from="/auth" to="/auth/login" exact />
</div>
);
}
const Home = () => <p>Home</p>;
const Dashboard = () => <p>Dashboard</p>;
function AppLayout() {
return (
<div>
<h1>App Layout</h1>
<Route path="/app/home" exact component={Home} />
<Route path="/app/dashboard" exact component={Dashboard} />
<Redirect from="/app" to="/app/home" exact />
</div>
);
}
如果您想保护某些未经身份验证的路由,也可以创建一个PrivateRoute
组件,如果未经身份验证,该组件将重定向到身份验证布局。
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props => sessionStorage.token // your auth mechanism goes here
? <Component {...props} />
: <Redirect to={{ pathname: '/auth' }} />}
/>
);
您可以使用此PrivateRoute
组件而不是react-router
的{{1}}组件。
例如:
Route
答案 3 :(得分:-1)
@Gaurab Kc和@johnny peter的两种解决方案都很棒,尽管我最终做了这样的事情:
Column name price is ambiguous
<Router history={history}>
<Switch>
<PrivateRoute
path="/home"
component={HomePage}>
</PrivateRoute>
<PrivateRoute
path="/dashboard"
component={DashboardPage}>
</PrivateRoute>
<AuthRoute
path="/login"
component={LoginPage}>
</AuthRoute>
<AuthRoute
path="/sign-up"
component={SignUpPage}>
</AuthRoute>
<Route path="*" component={NotFoundPage}/>
</Switch>
</Router>
和AuthRoute
类似于:
PrivateRoute
interface PrivateRouteProps extends RouteProps {
component: any;
}
const PrivateRoute = (props: PrivateRouteProps) => {
const {component: Component, ...rest} = props;
return (
<Route
{...rest}
render={(routeProps) =>
localStorage.getItem('user') ? (
<div>
... // here is the app header
<Component {...routeProps} />
.. // here is the app footer
</div>
) : (
<Redirect
to={{
pathname: '/login',
state: {from: routeProps.location}
}}
/>
)
}
/>
);
};
export default PrivateRoute;