I'm building a react app and I can't make the routing work.
I need one common layout (header, footer) for a few Auth routes (/login
, sign-up
, forgot-password
, etc...)
And I need need another common layout for the rest of the protected parts of the app (Home
, Dashboard
, etc...)
I need another 404 page without any layout.
I've tried several techniques from those links:
But could reach working version.
This is what I'm currently have:
(Note: for now I'm ignoring the need to block non logged-in users into the private routes of AppLayout, I'll handle that right after)
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;
Both AuthLayout
and AppLayout
are simple and similar to that (just with different header/footer for each):
class AppLayout extends Component {
render() {
return (
<div className="AppLayout">
<header>...</header>
{this.props.children}
<footer>...</footer>
</div>
);
}
}
export default AppLayout;
The problem is that only routes from the AppLayout are rendered.
Other routes just showing the AppLayout header
and footer
without any content.
Those are the react versions I'm using:
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0",
Any help would be appreciated.
Thanks in advance.
js application to implement nested routing in the current version of react-router that is React Router DOM version 6. We use nested routing in our application so that a parent component has control over its child component at the route level.
Set up Nested Tabs You do not need to configure static routes on top of tabs as React Router allows you to set up routes basically everywhere. Set up your path route to map to your to links. Note that the exact prop on the first route indicates a rigorous match.
This feature has been deprecated because the new structure of Routes is that they should act like components, so you should take advantage of component lifecycle methods instead.
The useNavigate() hook is introduced in the React Router v6 to replace the useHistory() hook.
Each of your layout should have a path component to differentiate from other layouts.
For example
Auth layouts could reside under /auth
eg, login would /auth/login
, signup would be /auth/signup
App layout could go under /app
eg, dashboard would be /app/dashboard
, home would be /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>
);
}
Also if you want to protect certain routes from being rendered if not authenticated, then you can create a PrivateRoute
component that would redirect to auth layout if not authenticated.
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props => sessionStorage.token // your auth mechanism goes here
? <Component {...props} />
: <Redirect to={{ pathname: '/auth' }} />}
/>
);
You can use this PrivateRoute
component instead of react-router
's Route
component.
Eg:
<PrivateRoute path="/app" component={AppLayout} />
It took me some time to find the answer that I favoured. Both @johnny-peter & @gaurab-kc solutions were great and they tought me about React's routing mechanism.
@johnny-peter 's solution had disadvantage of forcing me to put a prefix for all auth
related routes under /auth/...
(e.g. /auth/login
& auth/sign-up
) which I didn't wanted.
@gaurab-kc solution was supporting only one set of routes.. so if user was already signed up, he couldn't visit the /login
route anymore.
Up till recently I used my own solution which had the problem of "defeating the whole purpose of a common header and footer." as @johnny-peter mentioned and it was down-voted few times as it should be.
Now I'm using another solution:
<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>
which prevents all the above disadventages. It's allows me to:
/login
or other auth
routes without logout first.The only disadvantage of this solution is having more code and duplicating the routes, but it's a cost I'm willing to pay.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With