I am trying to separate my routes depending on views. To be specific I have created an admin view where I am going to have different routes for admin only. I am trying to use multiple switches but I keep getting 404.
The following is how I am doing:
App.js
<div className="App">
<Switch>
<Route exact path="/admin/dashboard" component={ AdminPanel } />
<Route component={ NoMatch } />
</Switch>
</div>
AdminPanel.js
<Link to="/admin/dashboard" className="sidebar-item">...</Link>
<Link to="/admin/dashboard/exams" className="sidebar-item">...</Link>
.
.
.
<div className="admin-content">
<Switch>
<Route exact path="/admin/dashboard" component={ Dashboard } />
<Route exact path="/admin/dashboard/exams" component={ Exam } />
</Switch>
</div>
When I visit localhost:3000/admin/dashboard I get to see the Dashboard component. But when I navigate to localhost:3000/admin/dashboard/exams I am greeted with the 404 page.
Where am I going wrong?
App.js:
<Switch>
<Route path="/admin/dashboard" component={ AdminPanel } />
<Route path="/404" component={ NoMatch } />
<Route component={ NoMatch } />
</Switch>
AdminPanel.js
import {Redirect} from 'react-router-dom'
<Switch>
<Route exact path="/admin/dashboard" component={ Dashboard } />
<Route exact path="/admin/dashboard/exams" component={ Exam } />
<Route render={({location}) => <Redirect to={{
pathname: '/404',
state: { originalUrl: location.pathname}
}} />} />
</Switch>
later in the NoMatch component, you can access it under props.location.state.originUrl
Related
I have one problem that I can not understand. I am totally a beginner in ReactJS so I hope you will help me. I made Navigation with React Router and it works, but when I start to render all other components in App.js nothings happened. When I am routing through the navigation bar it is rendering, but on scroll, nothing happened.
This is my App.js without rendering other components that work normally, but when I add something like , it is the same without scroll.
my code :
const App = () => {
return (
<div>
<Router>
<Topbar />
<About />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/service" component={Service} />
<Route path="/portfolio" component={Portfolio} />
<Route path="/contact" component={Contact} />
</Switch>
</Router>
</div>
);
};
export default App;
You need to use a redirect
1/ import {Redirect} from 'react-router-dom';
2/ Change your Home route to <Route exact path="/home" component={Home} />
3/ Add the redirect (It must be the last route)
<Route exact path="/">
<Redirect to="/home" />
</Route>
Example :
import React from 'react';
import {
BrowserRouter as Router,
Route,
Switch,
Redirect
} from 'react-router-dom';
import Home from './Home';
import About from './About';
import Service from './Service';
import Portfolio from './Portfolio';
import Contact from './Contact';
const App = () => {
return (
<Router>
<Switch>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/service" component={Service} />
<Route path="/portfolio" component={Portfolio} />
<Route path="/contact" component={Contact} />
{/* Redirect */}
<Route exact path="/">
<Redirect to="/home" />
</Route>
</Switch>
</Router>
);
};
export default App;
If you want to check a demo : Stackblitz
I have a basic portfolio app that has the following structure:
App.js
function App() {
return (
<BrowserRouter>
<LeftNav />
<RightNav />
<NavBar />
<Switch>
<Route component={Home} path='/' exact />
<Route component={About} path='/about' />
<Route component={Project} path='/projects' />
<Route component={Contact} path='/contact' />
</Switch>
</BrowserRouter>
)
}
When I click on the link to go the production site it only renders the LeftNav, RightNav, and Navbar. I have to click on the Home component to have the Home Screen load.
I then tried putting the Home component outside of to look like:
function App() {
return (
<BrowserRouter>
<LeftNav />
<RightNav />
<NavBar />
<Home />
<Switch>
<Route component={Home} path='/' exact />
<Route component={About} path='/about' />
<Route component={Project} path='/projects' />
<Route component={Contact} path='/contact' />
</Switch>
</BrowserRouter>
)
}
This is the action I want upon clicking on the link, however then my components don't load. How do I structure this so that the Home component loads up on the initial click and that I'm able to navigate to other pages?
Your first version is good, just add a redirect and change the home path
import React from 'react';
import {BrowserRouter, Switch, Route, Redirect} from 'react-router-dom'; // import Redirect
function App() {
return (
<BrowserRouter>
<LeftNav />
<RightNav />
<NavBar />
<Switch>
<Route component={Home} path='/home' exact /> // change the path
<Route component={About} path='/about' />
<Route component={Project} path='/projects' />
<Route component={Contact} path='/contact' />
<Route path="/" exact> // Add the redirect
<Redirect to="/home" />
</Route>
</Switch>
</BrowserRouter>
)
}
You will have to exchange your home path from being the default page:
<Route component={Home} path='/' exact />
to
<Route component={Home} path='/home' exact />
and then add a 'Redirect' to your App.js :
<Route path="/" exact>
<Redirect to="/home" />
</Route>
I'm having a problem regarding using of error page in my react app. The 404 page always shows at the bottom of every page that I render. I'm new to react. I hope someone can help me.
This is my App.js
import {BrowserRouter as Router,Switch,Route} from 'react-router-dom';
import Login from './components/auth/Login';
import Register from './components/auth/Register';
import ErrorPage from './components/ErrorPage';
import Order from './components/Order';
import Navbar from './components/partials/Navbar';
import Footer from './components/partials/Footer';
import Shop from './components/Shop';
import ItemDetails from './components/ItemDetails';
import Cart from './components/Cart';
import Customize from './components/Customize';
const App = () => {
return (
<>
<Router>
<Switch>
<Route exact path='/login'>
<Login />
</Route>
<Route exact path='/register'>
<Register />
</Route>
<div>
<Navbar />
<Route exact path='/'>
<Shop />
</Route>
<Route exact path='/order'>
<Order />
</Route>
<Route exact path='/item/details'>
<ItemDetails />
</Route>
<Route exact path='/cart'>
<Cart />
</Route>
<Route exact path='/customize'>
<Customize />
</Route>
<Route component={ErrorPage} />
</div>
</Switch>
</Router>
<Footer />
</>
);
}
export default App;
I searched about handling error page in react and I see that the order of routes is important but I don't get why I'm still getting the error page even it's in the bottom. Thank you guys.
That's because the switch component returns the first child at the root that meets the path condition. If the path condition doesn't exist it's evaluated as true. In your case you have 3 child Login, Register and the div which will always be evaluated to true. So just move all routes to the root of your switch:
<Router>
<Switch>
<Route exact path='/login'>
<Login />
</Route>
<Route exact path='/register'>
<Register />
</Route>
<div>
<Navbar />
<Switch>
<Route exact path='/'>
<Shop />
</Route>
<Route exact path='/order'>
<Order />
</Route>
<Route exact path='/item/details'>
<ItemDetails />
</Route>
<Route exact path='/cart'>
<Cart />
</Route>
<Route exact path='/customize'>
<Customize />
</Route>
<Route component={ErrorPage} />
</Switch>
</div>
</Switch>
</Router>
I have problem with common header in react js.
Currently login route is displaying common header and i dont want to show on my login page. If i go to contacts page than its showing common header which is perfect
import "./styles/App.scss";
import Navbar from "./components/elements/Navbar";
import Contacts from "./components/contacts/Contacts";
import { Provider } from "react-redux";
import store from "./store";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import AddContact from "./components/contacts/AddContact";
import EditContact from "./components/contacts/EditContact";
import Login from "./components/login/Login";
import Logout from "./components/logout/Logout";
function App(props) {
return (
<Provider store={ store }>
<Router>
<div className="App">
{props.location.pathname !== '/login' ? <Navbar/> : null}
<Route exact path="/login" component={ Login } />
<div className="container">
<div className="py-3">
<Switch>
<Route exact path="/" component={ Contacts } />
<Route exact path="/logout" component={ Logout } />
<Route exact path="/contacts/add" component={ AddContact } />
<Route
exact
path="/contacts/edit/:id"
component={ EditContact }
/>
</Switch>
</div>
</div>
</div>
</Router>
</Provider>
);
}
export default App;
[1]: https://i.stack.imgur.com/7V0qi.png
I think you meant to create Links in NavBar, not declare the Routes:
<Router>
<div className="App">
<div className="container">
<div className="py-3">
<Switch>
<Route exact path="/login" component={Login} />
<Route>
<Navbar />
<Switch>
<PrivateRoute exact path="/" component={Contacts} />
<PrivateRoute exact path="/logout" component={Logout} />
<PrivateRoute exact path="/contacts/add" component={AddContact} />
<PrivateRoute
exact
path="/contacts/edit/:id"
component={EditContact}
/>
</Switch>
</Route>
</Switch>
</div>
</div>
</div>
</Router>
NavBar:
function Navbar() {
const someId = 123 // example
return (
<>
<Link to="/">Login</Link>
<Link to="/logout">Logout</Link>
<Link to="/contacts/add">Add Contacts</Link>
<Link to={`/contacts/edit/${someId}`}>Edit Contact</Link>
</>
)
}
After this, you are most likely to be looking for authentication. I recently wrote an answer on authenticated or protected routes i.e. PrivateRoute.
Also, note that All children of a Switch should be Route or Redirect elements.
You can only show the <Navbar/> when it's not the login page and you need to keep the login page inside the switch for the pages to work.
return (
<Provider store={ store }>
<Router>
<div className="App">
{props.location.pathname !== '/login' ? <Navbar/> : null}
<div className="container">
<div className="py-3">
<Switch>
<Route exact path="/login" component={ Login } />
<Route exact path="/" component={ Contacts } />
<Route exact path="/logout" component={ Logout } />
<Route exact path="/contacts/add" component={ AddContact } />
<Route
exact
path="/contacts/edit/:id"
component={ EditContact }
/>
</Switch>
</div>
</div>
</div>
</Router>
</Provider>
);
I have my app and I want to add an admin routes. The problem is my header and footer are rendered on every route so when I'm trying to access admin panel they are rendered too. How can I separate 2 different routes for 2 different apps (not exactly but I hope u'll understand).
This is how my router looks like:
<Router>
<Container>
<Header/> // it is intended
<Switch>
<Route exact path='/' component={ Home } />
<Route path='/news/:category/:id/:title' component={ SingleArticle } />
<Route path='/news' component={ Home } />
<Route path='/live' component={ Live } />
<Route path='/admin' component={ AdminPanel } /> //here I want all my admin routes which generates its own header and footer
<Route path='*' component={ NotFound } />
</Switch>
<Footer /> // it is intended
</Container>
</Router>
You can have different routes for admin and non-admin. You can do following:
if(admin) {
return (
<Router>
<Header>
// ... routes here
</Header>
</Router>
)
} else {
return (
<Router>
<AdminHeader />
// ... routes
</Router>
)
}
You can make use of a layout type component that takes a component as a prop, adds the necessary components to it and returns an new component like so:
const Layout = ({ children }) => {
return (
<section>
<Header/>
{children}
<Footer/>
</section>
)
}
Then any component you want to render with the header and footer you can declare as a child of the layout component:
<Router>
<Container>
<Switch>
<Route path='/admin' component={ AdminPanel } /> //here I want all my admin routes which generates its own header and footer
<Layout>
<Route exact path='/' component={ Home } />
<Route path='/news/:category/:id/:title' component={ SingleArticle } />
<Route path='/news' component={ Home } />
<Route path='/live' component={ Live } />
<Route path='*' component={ NotFound } />
</Layout>
</Switch>
</Container>
</Router>
You can use useLocation() Hook to find paths and separate routes.
eg:
import { useLocation } from 'react-router-dom'
if (useLocation().pathname.includes("/admin")) {
return (
<Switch>
<Route exact path="/admin" component={Admin} />
</Switch>
);
} else {
return (
<div className="App">
<Navbar />
<Switch>
// Routes goes
</Switch>
</div>
);