React router is showing No Router matched - javascript

App.js
import Login from './Auth/components/login/Login';
import { Route, BrowserRouter, Routes, Outlet } from 'react-router-dom';
import SignIn from './Auth/components/signin/Signin';
import Home from './Home/Home';
import Dogs from './pets/Dogs';
import Cats from './pets/Cats';
import Others from './pets/Others';
import Pets from './pets/Pets';
import { Header } from './ui/Header/Header';
import { ContextClickValue } from './context/ContextClick';
import Cart from './Auth/components/cart/Cart';
function App() {
return (
<>
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} >
</Route>
</Routes>
<Header />
<Routes>
<Route path="/login" element={<Login />}></Route>
<Route path="/signin" element={<SignIn />}></Route>
<Route path="/cart" element={<Cart />}></Route>
<Route path="pets" element={< Outlet />}>
<Route index element={<Pets />} />
<Route path="dogs" element={<Dogs />} />
<Route path="cats" element={<Cats />} />
<Route path="others" element={<Others />} />
</Route>
</Routes>
</BrowserRouter>
</>
);
}
export default App;
Header.js
import { menuItems } from "../../Home/MenuItems";
import MenuItemComponent from "./MenuItemComponent";
import HeaderStyles from "./Header.module.css";
import { ContextClick, ContextClickValue } from "../../context/ContextClick";
import AddShoppingCartIcon from '#mui/icons-material/AddShoppingCart';
import {useSelector} from 'react-redux'
import { NavLink, useNavigate } from "react-router-dom";
export function Header() {
const cart = useSelector(state => state.cart.cart)
const navigate = useNavigate()
function navigateToCart(e){
e.preventDefault()
navigate('/cart')
}
let total = 0;
return (
<section className={HeaderStyles.navbar}>
<header>
<h4 className={HeaderStyles.logo}>PETSHOP</h4>
<nav>
<MenuItemComponent items={menuItems} />
</nav>
</header>
<section style={{ float:'right',margin:30, color:'white'}}>
<AddShoppingCartIcon style={{cursor:'pointer'}} onClick={navigateToCart}/>
{cart.forEach(item => {
total += item.quantity
})}
<span>{total}</span>
</section>
</section>
)
}
i have tried using Navlink also
<NavLink to="/cart">
<AddShoppingCartIcon style={{cursor:'pointer'}} />
{cart.forEach(item => {
total += item.quantity
})}
</NavLink>
I am trying to to navigate to cart (i don't know why it is not working)
In dev Tools it is showing to matching Router (i tried clearing cache and hard reload and restarted my server)
I have replaced cart to login for checking it is Navigation Successfully
sandBox link
https://codesandbox.io/p/github/muthyalaDivyaVenkatesh/authentication/master
Can Anyone let me know Why it is Not Working .

Issues
You are rendering 2 Header components, one inside the Home component within a Routes component, and another outside the routes on it's own. The Header renders links, one of which targets "/cart", but the Routes component isn't rendering a route for that path. The other Routes component is missing a route rendering on path "/".
Additionally, the Cart component isn't returning mapped JSX for the cart data selected from state.
function Cart() {
const cart = useSelector((state)=> state.cart.cart)
return (
<div>
{cart.map(cartItem => {
<ShoppingCard // <-- not returned!!
imageUrl={cartItem.imageUrl}
price={cartItem.price}
/>
})}
</div>
)
}
Solution
Create a layout component that renders the Header component, and remove the Header from the Home component.
App.js
const AppLayout = () => (
<>
<Header />
<Outlet />
</>
);
function App() {
return (
<>
<BrowserRouter>
<Routes>
<Route element={<AppLayout />}>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/signin" element={<SignIn />} />
<Route path="/cart" element={<Cart />} />
<Route path="pets">
<Route index element={<Pets />} />
<Route path="dogs" element={<Dogs />} />
<Route path="cats" element={<Cats />} />
<Route path="others" element={<Others />} />
</Route>
</Route>
</Routes>
</BrowserRouter>
</>
);
}
Home.js
export default function Home() {
return (
<>
<ImageChanging />
<TopDeals />
</>
);
}
Cart.js
function Cart() {
const cart = useSelector((state) => state.cart.cart);
return (
<div>
<h1>Cart</h1>
{cart.map((cartItem) => {
return ( // <-- return the ShoppingCard component
<ShoppingCard
width={300}
height={300}
{...cartItem}
/>
);
})}
</div>
);
}

Related

PrivateRoute in React-router-dom v6 isnt working

I'm trying to use ProtectedRoute as
I can't see why the code isn't working, I'm not getting any error, but at /account it should display <Profile/> and it's blank, I can see the header and footer, but the whole <Profile/> is missing
before trying to use a PrivateRoute, I could display Profile with any problem.
my ProtectedRoute.js
import React from "react";
import { useSelector } from "react-redux";
import { Navigate, Outlet } from "react-router-dom";
const ProtectedRoute = () => {
const {isAuthenticated} = useSelector((state)=>state.user)
return isAuthenticated ? <Outlet /> : <Navigate to="/login"/>
}
export default ProtectedRoute;
my app.js
function App() {
const {isAuthenticated, user} = useSelector(state=>state.user)
React.useEffect(() => {
WebFont.load({
google:{
families: [ "Droid Sans", "Chilanka"],
},
});
store.dispatch(loadUser())
}, []);
return (
<Router>
<Header/>
{isAuthenticated && <UserOptions user={user} />}
<Routes>
<Route exact path="/" element={<Home/>}/>
<Route exact path="/product/:id" element={<ProductDetails/>}/>
<Route exact path="/products" element={<Products/>}/>
<Route path="/products/:keyword" element={<Products/>}/>
<Route exact path="/search" element={<Search/>}/>
<Route exact path="/account" element={<ProtectedRoute/>}/>
<Route exact path="/account" element={<Profile/>}/>
<Route exact path="/login" element={<LoginSignUp/>}/>
</Routes>
<Footer/>
</Router>
);
}
export default App;
and my Profile
const Profile = () => {
const { user, loading, isAuthenticated} = useSelector((state) => state.user);
const navigate = useNavigate();
useEffect(() => {
if(isAuthenticated === false){
navigate("/login");
}
}, [navigate,isAuthenticated])
return (
<Fragment>
<MetaData title={`${user.name}'s Profile`} />
<div className="profileContainer">
<div>
<h1>My Profile</h1>
<img src={user.avatar?.url} alt={user.name} />
<Link to="/me/update">Edit Profile</Link>
</div>
<div>
<div>
<h4>Full Name</h4>
<p>{user.name}</p>
</div>
<div>
<h4>Email</h4>
<p>{user.email}</p>
</div>
<div>
<h4>Joined On</h4>
<p>{String(user.createdAt).substr(0, 10)}</p>
</div>
<div>
<Link to="/orders">My Orders</Link>
<Link to="/password/update">Change Password</Link>
</div>
</div>
</div>
</Fragment>
);
};
export default Profile;
You are rendering two routes for the same "/account" path. ProtectedRoute is rendered on its own self-closing route, so the second route rendering Profile is unreachable.
<Routes>
<Route exact path="/" element={<Home/>}/>
<Route exact path="/product/:id" element={<ProductDetails/>}/>
<Route exact path="/products" element={<Products/>}/>
<Route path="/products/:keyword" element={<Products/>}/>
<Route exact path="/search" element={<Search/>}/>
<Route exact path="/account" element={<ProtectedRoute/>}/>
<Route exact path="/account" element={<Profile/>}/> // <-- unreachable, oops!
<Route exact path="/login" element={<LoginSignUp/>}/>
</Routes>
Remove the path prop from the layout route rendering the ProtectedRoute and ensure it is actually wrapping other Route components. You may as well also remove the exact prop on all the routes as this prop was removed in RRDv6.
Example:
<Router>
<Header/>
{isAuthenticated && <UserOptions user={user} />}
<Routes>
<Route path="/" element={<Home />} />
<Route path="/product/:id" element={<ProductDetails />} />
<Route path="/products" element={<Products />} />
<Route path="/products/:keyword" element={<Products />} />
<Route path="/search" element={<Search />} />
<Route element={<ProtectedRoute />}>
<Route path="/account" element={<Profile />} /> // <-- wrapped by layout route!
</Route>
<Route path="/login" element={<LoginSignUp />} />
</Routes>
<Footer/>
</Router>
The ProtectedRoute component doesn't appear to wait for the user state to populate before rendering either the Outlet for protected content or the redirect. Apply some conditional rendering to render a loading indicator or similar while the user state is populated.
import React from "react";
import { useSelector } from "react-redux";
import { Navigate, Outlet } from "react-router-dom";
const ProtectedRoute = () => {
const user = useSelector((state) => state.user);
if (!user) return null; // <-- or loading indicator, etc...
return user.isAuthenticated
? <Outlet />
: <Navigate to="/login" replace />;
}
export default ProtectedRoute;

useEffect() is not able to load data for the second time as soon as the page loaded manually

this is app.js
import Header from './components/Header/Header';
import Login from './components/Login/Login';
import { BrowserRouter as Router, Route,Routes } from "react-router-dom";
import Register from './components/Register/Register';
import About from './components/About/About';
import Update from './components/Update/Update';
import Contact from './components/Contact/Contact';
import Home from './components/Home/Home';
import Logout from './components/Logout/Logout';
import Project from './components/Project/Project';
import Error from './components/Error';
import { useDispatch,useSelector } from 'react-redux';
import { useEffect } from 'react';
import { loadUser } from './actions/userActions';
function App() {
const dispatch = useDispatch();
const {loading, user} = useSelector((state) => state.user);
useEffect(() => {
dispatch(loadUser());
}, [dispatch]);
return (
<div className="App">
<Router>
<Header />
<Routes>
<Route exact path="/" element={<Home
userhome = {user} />} />
<Route exact path="/login" element={<Login />} />
<Route exact path="/signup" element={<Register />} />
<Route exact path="/about" element={<About /> } />
<Route exact path="/update" element={<Update /> } />
<Route exact path="/contact" element={<Contact /> } />
<Route exact path="/logout" element={<Logout /> } />
<Route exact path="/project" element={<Project /> } />
<Route exact path="/profile" element={<About /> } />
<Route path="*" element={<Error />} />
</Routes>
</Router>
</div>
);
}
export default App;
this is home.js
in any react app, "localhost:3000" will automatically get rendered (if there is no error).
In my case also same thing is happening, when the react app loads for the first time, it does not give any error.
The output for first time is Name : Prajwal Raj
But as soon as i load the same home route for second time is gives error ,
Cannot read properties of undefined (reading 'name')
const Home = ({userhome}) =>{
return (
<div className="home">
<h1>HOME</h1>
<p>Name : {userhome.name}</p>
</div>
);
};
export default Home;

How can I split React Router into multiple files

My routes file is getting rather messy so I decided to split them out into separate files.
My problem is that if I used 2 separate files, whichever comes after the first include does not get rendered:
const routes = (
<div>
<Switch>
<Route exact path="/" component={Home} />
{Registration} //Does get rendered
//Everything below this does not get a route
{Faq}
<Route path="/login" component={login} />
<Route component={NoMatch} />
</Switch>
</div>
);
If I switch Faq with registration then all the Faq routes will work.
RegistrationRoutes.js
import Introduction from '../containers/Registration/Introduction';
import Login from '../containers/Login';
const Routes = (
<Switch>
<Route path="/login" component={Login} key="login" />,
<Route path="/registration/introduction" component={Introduction} key="registration-intro" />
</Switch>
);
export default Routes;
FaqRoutes.js
import Faq from '../containers/Faq';
import faqJson from '../json_content/faq/faq';
import FaqCategory from '../containers/Faq/faqCategory';
const Routes = (
<Switch>
<Route path="/faq/:category" component={FaqCategory} key="faqCat" />
<Route path="/faq" render={props => <Faq data={faqJson} />} key="faq" />
</Switch>
);
export default Routes;
May be you can move them to config file and load them from there.
App.tsx
import routes from "./routes";
const App: React.FC = () => {
return (
<BrowserRouter>
<div>
<Switch>
{routes.data.map((entry) => {return (<Route {...entry}/>)})}
</Switch>
</div>
</BrowserRouter>
);
};
export default App;
router.ts
const routes = {data: [
{
key: "one",
path: "/three"
},
{
key: "two",
path: "/two"
}
]
}
export default routes;
This will keep your code simple
Your code would get translated to something like this,
const routes = (
<div>
<Switch>
<Route exact path="/" component={Home} />
<Switch>
<Route path="/login" component={Login} key="login" />,
<Route path="/registration/introduction"
component={Introduction} key="registration-intro" />
</Switch>
//Everything below this does not get a route
{Faq}
<Route path="/login" component={login} />
<Route component={NoMatch} />
</Switch>
</div>
);
This is wrong way to implement routing with react-router-dom or React-Router v4.
For Correct way of implementation You can see this example.
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Switch, Route, Link } from "react-router-dom";
import LandingPage from "../Registration";
const Home = () => {
return <div>
Home Component
<Link to="/auth/login">Login</Link>
</div>;
};
function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/auth" component={LandingPage} />
</Switch>
</BrowserRouter>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Registration.js
import React, { Component } from 'react';
import { Switch, Route, Link, Redirect } from 'react-router-dom';
const LoginRegister = (props) => {
return (
<div>
Login or register
<Link to="/login">Login</Link>
<br />
<Link to="/signup" >Signup</Link>
</div>
);
}
const Login = (props) =>{
console.log("login ", props);
return (
<div>
Login Component
<Link to="/auth/signup" >Signup</Link>
</div>
);
}
const Signup = () => (
<div>
Signup component
<Link to="/auth/login" >Login</Link>
</div>
);
class LandingPage extends Component {
render() {
console.log('Landing page',this.props);
const loginPath = this.props.match.path +'/login';
const signupPath = this.props.match.path + '/signup';
console.log(loginPath);
return (
<div className="container" >
Landing page
<Switch>
<Route path={loginPath} component={Login} />
<Route path={signupPath} component={Signup} />
<Route path="/" exact component={LoginRegister} />
</Switch>
</div>
);
}
}
export default LandingPage;
Try the following
RegistrationRoutes.js
import Introduction from '../containers/Registration/Introduction';
import Login from '../containers/Login';
const Routes = (
<React.Fragment>
<Route path="/login" component={Login} key="login" />,
<Route path="/registration/introduction" component={Introduction} key="registration-intro" />
</React.Fragment>
);
export default Routes;

How to skip header and footer for certain routes in ReactJS?

I have the following code which renders an app with a header and footer for all pages.
app.js
import React from 'react';
import {
Route,
Switch
} from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router'
import Layout from './components/Layout'
import Home from './homeComponent';
import Login from './loginComponent';
import Dashboard from './dashboardComponent';
const App = ({ history }) => {
return (
<Layout>
<ConnectedRouter history={history}>
<Switch>
<Route exact={true} path="/" component={Home} />
<Route path="/login" component={Login} />
<Route path="/dashboard" component={Dashboard} />
... more routes
<Route component={NoMatch} />
</Switch>
</ConnectedRouter>
</Layout>
);
};
export default App;
layout.js
import Header from './headerComponent'
import Footer from './footerComponent'
import React, {Component} from 'react'
class Layout extends Component {
render() {
return (
<div>
<Header />
{this.props.children}
<Footer />
</div>
)
}
}
What is the best way to skip rendering of the header and footer for certain pages like Home and Login routes?
I'd recommend creating two layouts with their own header and footers and a private route:
Public Layout
export const PublicLayout = (props) => <div>
<PublicHeader/>
<Switch>
<Route exact path="/" component={HomePage}/>
<Route exact path='/signin' component={SigninForm} />
<Route exact path='/signup' component={Signup} />
</Switch>
<PublicFooter/>
Protected Layout
export const ProtectedLayout = (props) => <div>
<ProtectedHeader/>
<Switch>
<PrivateRoute exact path='/app/dashboard' component={Dashboard} />
<Route component={NotFound} />
</Switch>
<ProtectedFooter/>
Define high-level routes in app.js:
export default () => {
return <div>
<Switch>
<Route path='/app' component={ProtectedLayout} />
<Route path='/' component={PublicLayout} />
</Switch>
</div>
}
Define PrivateRoute:
export default ({component: Component, ...rest}) => (
<Route {...rest} render={props => (
window.globalState.isAuthenticated() ? (
<Component {...props} />
) : (
<Redirect to={{
pathname: '/signin',
state: {from: props.location}
}} />
)
)} />
)
Yeah i know a bit late .
Visual studio 2019
import React from 'react';
import { Container } from 'reactstrap';
import NavMenu from '../components/NavMenu';
export default props => (
<div>
{window.location.pathname !== '/login' ? <NavMenu /> : null}
<Container>
{props.children}
</Container>
</div>
);
i hope somebody helps out there.. !!! Happy coding
I made some solution while solving the problem.
First You can wrap the Switch in a website header and footer
<BrowserRouter>
<WebsiteHeader />
<Switch>
<Route/>
<Route/>
<Route/>
</Switch>
<WebsiteFooter/>
<BrowserRouter>
then inside the header or footer wrap the components using withRouter from 'react-router-dom' so you can access the routes props
const WebsiteHeader = props => {
if (props.location.pathname == "/register") return null;
return (
<Fragment>
<DesktopHeader {...props} />
<MobileHeader {...props} />
</Fragment>
);
};
export default withRouter(WebsiteHeader);
Use render
<ConnectedRouter history={history}>
<Switch>
<Route path="/dashboard" render={props => <Layout><Dashboard {...props} /></Layout>} />
<Route path="/login" component={Login} />
</Switch>
</ConnectedRouter>
For forcefully refresh Header inside routing.
use forceRefresh={true}
const Routing = () => {
return(
<BrowserRouter forceRefresh={true}>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/list/:id" component={ListingApi}/>
<Route path="/details/:id" component={HotelDetails}/>
<Route path="/booking/:hotel_name" component={PlaceBooking}/>
<Route path="/viewBooking" component={ViewBooking}/>
<Route exact path="/login" component={LoginComponent}/>
<Route path="/signup" component={RegisterComponent}/>
</Switch>
<Footer/>
</BrowserRouter>
)
}
I would just create a few different layouts one with header and footer and one without. And then instead of wrapping everything into one layout. I'd just do this wrapping inside each page component. So your components would be like:
Dashboard component
<SimpleLayout>
<Dashboard>
</SimpleLayout>
Home component
<MainLayout>
<Home>
</MainLayout>
Try like this
<Route path="/" render={(props) => (props.location.pathname !== "/login") &&
<Header />}>
</Route>
<Route path="/" render={(props) => (props.location.pathname !== "/login") &&
<Menu />}>
</Route>
<PrivateRoute path="/scope" component={Scope} ></PrivateRoute>
<Route exact path="/login" component={Login} />
In this example I'm checking the URL, If the URL is "/Login" I'm removing Menu and header component
For forcefully refresh Header inside routing.
const Routing = () => {
return(
<BrowserRouter forceRefresh={true}>
<Header/>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/list/:id" component={ListingApi}/>
<Route path="/details/:id" component={HotelDetails}/>
<Route path="/booking/:hotel_name" component={PlaceBooking}/>
<Route path="/viewBooking" component={ViewBooking}/>
<Route exact path="/login" component={LoginComponent}/>
<Route path="/signup" component={RegisterComponent}/>
</Switch>
<Footer/>
</BrowserRouter>
)
}

Nested routes with react router v4 / v5

I am currently struggling with nesting routes using react router v4.
The closest example was the route config in the
React-Router v4 Documentation.
I want to split my app in 2 different parts.
A frontend and an admin area.
I was thinking about something like this:
<Match pattern="/" component={Frontpage}>
<Match pattern="/home" component={HomePage} />
<Match pattern="/about" component={AboutPage} />
</Match>
<Match pattern="/admin" component={Backend}>
<Match pattern="/home" component={Dashboard} />
<Match pattern="/users" component={UserPage} />
</Match>
<Miss component={NotFoundPage} />
The frontend has a different layout and style than the admin area. So within the frontpage the route home, about and so one should be the child routes.
/home should be rendered into the Frontpage component and /admin/home should be rendered within the Backend component.
I tried some other variations but I always ended in not hitting /home or /admin/home.
Final solution:
This is the final solution I am using right now. This example also has a global error component like a traditional 404 page.
import React, { Component } from 'react';
import { Switch, Route, Redirect, Link } from 'react-router-dom';
const Home = () => <div><h1>Home</h1></div>;
const User = () => <div><h1>User</h1></div>;
const Error = () => <div><h1>Error</h1></div>
const Frontend = props => {
console.log('Frontend');
return (
<div>
<h2>Frontend</h2>
<p><Link to="/">Root</Link></p>
<p><Link to="/user">User</Link></p>
<p><Link to="/admin">Backend</Link></p>
<p><Link to="/the-route-is-swiggity-swoute">Swiggity swooty</Link></p>
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/user' component={User}/>
<Redirect to={{
state: { error: true }
}} />
</Switch>
<footer>Bottom</footer>
</div>
);
}
const Backend = props => {
console.log('Backend');
return (
<div>
<h2>Backend</h2>
<p><Link to="/admin">Root</Link></p>
<p><Link to="/admin/user">User</Link></p>
<p><Link to="/">Frontend</Link></p>
<p><Link to="/admin/the-route-is-swiggity-swoute">Swiggity swooty</Link></p>
<Switch>
<Route exact path='/admin' component={Home}/>
<Route path='/admin/user' component={User}/>
<Redirect to={{
state: { error: true }
}} />
</Switch>
<footer>Bottom</footer>
</div>
);
}
class GlobalErrorSwitch extends Component {
previousLocation = this.props.location
componentWillUpdate(nextProps) {
const { location } = this.props;
if (nextProps.history.action !== 'POP'
&& (!location.state || !location.state.error)) {
this.previousLocation = this.props.location
};
}
render() {
const { location } = this.props;
const isError = !!(
location.state &&
location.state.error &&
this.previousLocation !== location // not initial render
)
return (
<div>
{
isError
? <Route component={Error} />
: <Switch location={isError ? this.previousLocation : location}>
<Route path="/admin" component={Backend} />
<Route path="/" component={Frontend} />
</Switch>}
</div>
)
}
}
class App extends Component {
render() {
return <Route component={GlobalErrorSwitch} />
}
}
export default App;
In react-router-v4 you don't nest <Routes />. Instead, you put them inside another <Component />.
For instance
<Route path='/topics' component={Topics}>
<Route path='/topics/:topicId' component={Topic} />
</Route>
should become
<Route path='/topics' component={Topics} />
with
const Topics = ({ match }) => (
<div>
<h2>Topics</h2>
<Link to={`${match.url}/exampleTopicId`}>
Example topic
</Link>
<Route path={`${match.path}/:topicId`} component={Topic}/>
</div>
)
Here is a basic example straight from the react-router documentation.
react-router v6
Update for 2022 - v6 has nested Route components that Just Work™.
This question is about v4/v5, but the best answer now is just use v6 if you can!
See example code in this blog post. If you can't upgrade just yet, however...
react-router v4 & v5
It's true that in order to nest Routes you need to place them in the child component of the Route.
However if you prefer a more inline syntax rather than breaking your Routes up across components, you can provide a functional component to the render prop of the Route you want to nest under.
<BrowserRouter>
<Route path="/" component={Frontpage} exact />
<Route path="/home" component={HomePage} />
<Route path="/about" component={AboutPage} />
<Route
path="/admin"
render={({ match: { url } }) => (
<>
<Route path={`${url}/`} component={Backend} exact />
<Route path={`${url}/home`} component={Dashboard} />
<Route path={`${url}/users`} component={UserPage} />
</>
)}
/>
</BrowserRouter>
If you're interested in why the render prop should be used, and not the component prop, it's because it stops the inline functional component from being remounted on every render. See the documentation for more detail.
Note the example wraps the nested Routes in a Fragment. Prior to React 16, you can use a container <div> instead.
Just wanted to mention react-router v4 changed radically since this question was posted/answed.
There is no <Match> component any more! <Switch>is to make sure only the first match is rendered. <Redirect> well .. redirects to another route. Use or leave out exact to either in- or exclude a partial match.
See the docs. They are great. https://reacttraining.com/react-router/
Here's an example I hope is useable to answer your question.
<Router>
<div>
<Redirect exact from='/' to='/front'/>
<Route path="/" render={() => {
return (
<div>
<h2>Home menu</h2>
<Link to="/front">front</Link>
<Link to="/back">back</Link>
</div>
);
}} />
<Route path="/front" render={() => {
return (
<div>
<h2>front menu</h2>
<Link to="/front/help">help</Link>
<Link to="/front/about">about</Link>
</div>
);
}} />
<Route exact path="/front/help" render={() => {
return <h2>front help</h2>;
}} />
<Route exact path="/front/about" render={() => {
return <h2>front about</h2>;
}} />
<Route path="/back" render={() => {
return (
<div>
<h2>back menu</h2>
<Link to="/back/help">help</Link>
<Link to="/back/about">about</Link>
</div>
);
}} />
<Route exact path="/back/help" render={() => {
return <h2>back help</h2>;
}} />
<Route exact path="/back/about" render={() => {
return <h2>back about</h2>;
}} />
</div>
</Router>
Hope it helped, let me know. If this example is not answering your question well enough, tell me and I'll see if I can modify it.
I succeeded in defining nested routes by wrapping with Switch and define nested route before than root route.
<BrowserRouter>
<Switch>
<Route path="/staffs/:id/edit" component={StaffEdit} />
<Route path="/staffs/:id" component={StaffShow} />
<Route path="/staffs" component={StaffIndex} />
</Switch>
</BrowserRouter>
Reference: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Switch.md
Using Hooks
The latest update with hooks is to use useRouteMatch.
Main routing component
export default function NestingExample() {
return (
<Router>
<Switch>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</Router>
);
}
Child component
function Topics() {
// The `path` lets us build <Route> paths
// while the `url` lets us build relative links.
let { path, url } = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<h5>
<Link to={`${url}/otherpath`}>/topics/otherpath/</Link>
</h5>
<ul>
<li>
<Link to={`${url}/topic1`}>/topics/topic1/</Link>
</li>
<li>
<Link to={`${url}/topic2`}>/topics/topic2</Link>
</li>
</ul>
// You can then use nested routing inside the child itself
<Switch>
<Route exact path={path}>
<h3>Please select a topic.</h3>
</Route>
<Route path={`${path}/:topicId`}>
<Topic />
</Route>
<Route path={`${path}/otherpath`>
<OtherPath/>
</Route>
</Switch>
</div>
);
}
Some thing like this.
import React from 'react';
import {
BrowserRouter as Router, Route, NavLink, Switch, Link
} from 'react-router-dom';
import '../assets/styles/App.css';
const Home = () =>
<NormalNavLinks>
<h1>HOME</h1>
</NormalNavLinks>;
const About = () =>
<NormalNavLinks>
<h1>About</h1>
</NormalNavLinks>;
const Help = () =>
<NormalNavLinks>
<h1>Help</h1>
</NormalNavLinks>;
const AdminHome = () =>
<AdminNavLinks>
<h1>root</h1>
</AdminNavLinks>;
const AdminAbout = () =>
<AdminNavLinks>
<h1>Admin about</h1>
</AdminNavLinks>;
const AdminHelp = () =>
<AdminNavLinks>
<h1>Admin Help</h1>
</AdminNavLinks>;
const AdminNavLinks = (props) => (
<div>
<h2>Admin Menu</h2>
<NavLink exact to="/admin">Admin Home</NavLink>
<NavLink to="/admin/help">Admin Help</NavLink>
<NavLink to="/admin/about">Admin About</NavLink>
<Link to="/">Home</Link>
{props.children}
</div>
);
const NormalNavLinks = (props) => (
<div>
<h2>Normal Menu</h2>
<NavLink exact to="/">Home</NavLink>
<NavLink to="/help">Help</NavLink>
<NavLink to="/about">About</NavLink>
<Link to="/admin">Admin</Link>
{props.children}
</div>
);
const App = () => (
<Router>
<div>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/help" component={Help}/>
<Route path="/about" component={About}/>
<Route exact path="/admin" component={AdminHome}/>
<Route path="/admin/help" component={AdminHelp}/>
<Route path="/admin/about" component={AdminAbout}/>
</Switch>
</div>
</Router>
);
export default App;
A complete answer for React Router v6 or version 6 just in case needed.
import Dashboard from "./dashboard/Dashboard";
import DashboardDefaultContent from "./dashboard/dashboard-default-content";
import { Route, Routes } from "react-router";
import { useRoutes } from "react-router-dom";
/*Routes is used to be Switch*/
const Router = () => {
return (
<Routes>
<Route path="/" element={<LandingPage />} />
<Route path="games" element={<Games />} />
<Route path="game-details/:id" element={<GameDetails />} />
<Route path="dashboard" element={<Dashboard />}>
<Route path="/" element={<DashboardDefaultContent />} />
<Route path="inbox" element={<Inbox />} />
<Route path="settings-and-privacy" element={<SettingsAndPrivacy />} />
<Route path="*" element={<NotFound />} />
</Route>
<Route path="*" element={<NotFound />} />
</Routes>
);
};
export default Router;
import DashboardSidebarNavigation from "./dashboard-sidebar-navigation";
import { Grid } from "#material-ui/core";
import { Outlet } from "react-router";
const Dashboard = () => {
return (
<Grid
container
direction="row"
justify="flex-start"
alignItems="flex-start"
>
<DashboardSidebarNavigation />
<Outlet />
</Grid>
);
};
export default Dashboard;
Github repo is here. https://github.com/webmasterdevlin/react-router-6-demo
React Router v6
allows to use both nested routes (like in v3) and separate, splitted routes (v4, v5).
Nested Routes
Keep all routes in one place for small/medium size apps:
<Routes>
<Route path="/" element={<Home />} >
<Route path="user" element={<User />} />
<Route path="dash" element={<Dashboard />} />
</Route>
</Routes>
const App = () => {
return (
<BrowserRouter>
<Routes>
// /js is start path of stack snippet
<Route path="/js" element={<Home />} >
<Route path="user" element={<User />} />
<Route path="dash" element={<Dashboard />} />
</Route>
</Routes>
</BrowserRouter>
);
}
const Home = () => {
const location = useLocation()
return (
<div>
<p>URL path: {location.pathname}</p>
<Outlet />
<p>
<Link to="user" style={{paddingRight: "10px"}}>user</Link>
<Link to="dash">dashboard</Link>
</p>
</div>
)
}
const User = () => <div>User profile</div>
const Dashboard = () => <div>Dashboard</div>
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://unpkg.com/react#16.13.1/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/history#5.0.0/umd/history.production.min.js"></script>
<script src="https://unpkg.com/react-router#6.0.0-alpha.5/umd/react-router.production.min.js"></script>
<script src="https://unpkg.com/react-router-dom#6.0.0-alpha.5/umd/react-router-dom.production.min.js"></script>
<script>var { BrowserRouter, Routes, Route, Link, Outlet, useNavigate, useLocation } = window.ReactRouterDOM;</script>
Alternative: Define your routes as plain JavaScript objects via useRoutes.
Separate Routes
You can use separates routes to meet requirements of larger apps like code splitting:
// inside App.jsx:
<Routes>
<Route path="/*" element={<Home />} />
</Routes>
// inside Home.jsx:
<Routes>
<Route path="user" element={<User />} />
<Route path="dash" element={<Dashboard />} />
</Routes>
const App = () => {
return (
<BrowserRouter>
<Routes>
// /js is start path of stack snippet
<Route path="/js/*" element={<Home />} />
</Routes>
</BrowserRouter>
);
}
const Home = () => {
const location = useLocation()
return (
<div>
<p>URL path: {location.pathname}</p>
<Routes>
<Route path="user" element={<User />} />
<Route path="dash" element={<Dashboard />} />
</Routes>
<p>
<Link to="user" style={{paddingRight: "5px"}}>user</Link>
<Link to="dash">dashboard</Link>
</p>
</div>
)
}
const User = () => <div>User profile</div>
const Dashboard = () => <div>Dashboard</div>
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://unpkg.com/react#16.13.1/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/history#5.0.0/umd/history.production.min.js"></script>
<script src="https://unpkg.com/react-router#6.0.0-alpha.5/umd/react-router.production.min.js"></script>
<script src="https://unpkg.com/react-router-dom#6.0.0-alpha.5/umd/react-router-dom.production.min.js"></script>
<script>var { BrowserRouter, Routes, Route, Link, Outlet, useNavigate, useLocation } = window.ReactRouterDOM;</script>
You can try something like
Routes.js
import React, { Component } from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom';
import FrontPage from './FrontPage';
import Dashboard from './Dashboard';
import AboutPage from './AboutPage';
import Backend from './Backend';
import Homepage from './Homepage';
import UserPage from './UserPage';
class Routes extends Component {
render() {
return (
<div>
<Route exact path="/" component={FrontPage} />
<Route exact path="/home" component={Homepage} />
<Route exact path="/about" component={AboutPage} />
<Route exact path="/admin" component={Backend} />
<Route exact path="/admin/home" component={Dashboard} />
<Route exact path="/users" component={UserPage} />
</div>
)
}
}
export default Routes
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Routes from './Routes';
class App extends Component {
render() {
return (
<div className="App">
<Router>
<Routes/>
</Router>
</div>
);
}
}
export default App;
I think you can achieve the same from here also.
A complete answer for React Router v5.
const Router = () => {
return (
<Switch>
<Route path={"/"} component={LandingPage} exact />
<Route path={"/games"} component={Games} />
<Route path={"/game-details/:id"} component={GameDetails} />
<Route
path={"/dashboard"}
render={({ match: { path } }) => (
<Dashboard>
<Switch>
<Route
exact
path={path + "/"}
component={DashboardDefaultContent}
/>
<Route path={`${path}/inbox`} component={Inbox} />
<Route
path={`${path}/settings-and-privacy`}
component={SettingsAndPrivacy}
/>
<Redirect exact from={path + "/*"} to={path} />
</Switch>
</Dashboard>
)}
/>
<Route path="/not-found" component={NotFound} />
<Redirect exact from={"*"} to={"/not-found"} />
</Switch>
);
};
export default Router;
const Dashboard = ({ children }) => {
return (
<Grid
container
direction="row"
justify="flex-start"
alignItems="flex-start"
>
<DashboardSidebarNavigation />
{children}
</Grid>
);
};
export default Dashboard;
Github repo is here. https://github.com/webmasterdevlin/react-router-5-demo
I prefer to use react function. This solution is short and more readable
const MainAppRoutes = () => (
<Switch>
<Route exact path='/' component={HomePage} />
{AdminRoute()}
{SampleRoute("/sample_admin")}
</Switch>
);
/*first implementation: without params*/
const AdminRoute = () => ([
<Route path='/admin/home' component={AdminHome} />,
<Route path='/admin/about' component={AdminAbout} />
]);
/*second implementation: with params*/
const SampleRoute = (main) => ([
<Route path={`${main}`} component={MainPage} />,
<Route path={`${main}/:id`} component={MainPage} />
]);
**This code worked for me with v6**
index.js
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="login" element={<Login />} />
<Route path="home" element={<Home />} />
</Route>
</Routes>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
App.js:
function App(props) {
useEffect(() => {
console.log('reloaded');
// Checking, if Parent component re-rendering or not *it should not be, in the sense of performance*, this code doesn't re-render parent component while loading children
});
return (
<div className="App">
<Link to="login">Login</Link>
<Link to="home">Home</Link>
<Outlet /> // This line is important, otherwise we will be shown with empty component
</div>
);
}
login.js:
const Login = () => {
return (
<div>
Login Component
</div>
)
};
home.js:
const Home= () => {
return (
<div>
Home Component
</div>
)
};
interface IDefaultLayoutProps {
children: React.ReactNode
}
const DefaultLayout: React.SFC<IDefaultLayoutProps> = ({children}) => {
return (
<div className="DefaultLayout">
{children}
</div>
);
}
const LayoutRoute: React.SFC<IDefaultLayoutRouteProps & RouteProps> = ({component: Component, layout: Layout, ...rest}) => {
const handleRender = (matchProps: RouteComponentProps<{}, StaticContext>) => (
<Layout>
<Component {...matchProps} />
</Layout>
);
return (
<Route {...rest} render={handleRender}/>
);
}
const ScreenRouter = () => (
<BrowserRouter>
<div>
<Link to="/">Home</Link>
<Link to="/counter">Counter</Link>
<Switch>
<LayoutRoute path="/" exact={true} layout={DefaultLayout} component={HomeScreen} />
<LayoutRoute path="/counter" layout={DashboardLayout} component={CounterScreen} />
</Switch>
</div>
</BrowserRouter>
);

Categories

Resources