app.js
import { BrowserRouter as Switch, Route } from "react-router-dom";
import Login from "./Pages/Login";
import ViewPurchaseOrders from "./Pages/purchases/ViewPurchaseOrders";
import ViewProductSelectionGrn from "./Pages/GRN Management/View.product.selection-grn";
import Error from "./Components/404page/Error";
function App() {
return (
<div>
<Switch>
<Route path="/" exact component={Login} />
<ProtectedRoute
exact
path="/confirm-purchase-orders"
component={ViewPurchaseOrders}
/>
<ProtectedRoute
exact
path="/grn-product-selections"
component={ViewProductSelectionGrn}
/>
<Route path="*">{Error}</Route>
</Switch>
</div>
);
}
export default App;
404 page is rendering everywhere like above attached picture. I need to fix it. I tried few ways but it doesn't work properly.
Issue
The issue here is that you've managed to import the BrowserRouter as a Switch, so the Switch is really just a plain old router and all routes are being inclusively matched and rendered, i.e. all matching routes are rendered. Routes rendering on path="*" will always be matched and rendered.
import {
BrowserRouter as Switch, // <-- whoopsies!
Route
} from "react-router-dom";
...
function App() {
return (
<div>
<Switch> // <-- BrowserRouter in disguise
<Route path="/" exact component={Login} />
<ProtectedRoute
exact
path="/confirm-purchase-orders"
component={ViewPurchaseOrders}
/>
<ProtectedRoute
exact
path="/grn-product-selections"
component={ViewProductSelectionGrn}
/>
<Route path="*">{Error}</Route> // <-- always rendered
</Switch>
</div>
);
}
Solution
Import the BrowserRouter as a Router, then import the Switch and continue to render the routes into it so they are exclusively matched and rendered, i.e. only one match.
Example:
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
...
function App() {
return (
<div>
<Router>
<Switch>
<ProtectedRoute
path="/confirm-purchase-orders"
component={ViewPurchaseOrders}
/>
<ProtectedRoute
path="/grn-product-selections"
component={ViewProductSelectionGrn}
/>
<Route path="/" component={Login} />
<Route path="*">{Error}</Route>
</Switch>
</Router>
</div>
);
}
Related
I have just started with React and not able to get the router working. Below is the code for router. If I use the individual components without the router, they are displayed on the screen. But with router I don't get any text on the screen across any of the paths.
Please let me know if I am missing something. Below is the code:
import { Route } from 'react-router-dom';
import AllMeetupsPage from './pages/AllMeetups';
import NewMeetupPage from './pages/NewMeetup';
function App() {
return (
<div>
<Route path='/' exact>
<AllMeetupsPage />
</Route>
<Route path='/new-meetup'>
<NewMeetupPage />
</Route>
</div>);
}
export default App;
A route needs to be a descendent of router component. I'm not sure which version of react-router you're using, but this will be a BrowserRouter and Routes component for react-router v6 and on v4/v5 it'll be a BrowserRouter
Here's some examples:
v6:
import {
BrowserRouter,
Routes,
Route
} from "react-router-dom";
import AllMeetupsPage from './pages/AllMeetups';
import NewMeetupPage from './pages/NewMeetup';
function App() {
return (
<div>
<BrowserRouter>
<Routes>
<Route path="/" exact element={<AllMeetupsPage />}/>
<Route path="/new-meetup" element={<NewMeetupPage />}/>
</Routes>
</BrowserRouter>
</div>);
}
export default App;
You missed using Switch component
import { Route , Switch } from 'react-router-dom';
function App() {
return (
<div>
<Switch>
<Route path='/' exact>
<AllMeetupsPage />
</Route>
<Route path='/new-meetup'>
<NewMeetupPage />
</Route>
</Switch>
</div>);
}
export default App;
I'm currently getting troubled with the react router dom#6. Like, I want to redirect users to other pages If they logged in. But when I use Navigate component It threw error saying that :
"[Navigate] is not a component. All component children of Routes must be a Route or React.Fragment"
Though I have wrapped it in the fragment but the result still the same. Please help me, this is my code:
import {BrowserRouter as Router, Routes, Route, Navigate} from 'react-router-dom';
import Home from './pages/Home';
import ProductList from './pages/ProductList';
import Product from './pages/Product';
import Register from './pages/Register';
import Login from './pages/Login';
import Cart from './pages/Cart';
import ErrorPage from './pages/ErrorPage';
function App() {
const user = true;
return (
<Router>
<Routes>
<Route path="/" element={<Home/>} />
<Route path="/products/:category" element={<ProductList/>} />
<Route path="/product/:id" element={<Product/>} />
<Route path="/cart" element={<Cart/>} />
<Route path="/dang-ky" element={<Register/>} />
<Route path="/dang-nhap" element={<Login/>} >
{user ? <><Navigate to="/" replace/></> : <Login/>}
</Route>
<Route path="*" element={<ErrorPage/>} />
</Routes>
</Router>
);
}
export default App;
You can simply use Navigate component from 'react-router-dom' library and use it to redirect inside the element attribute of the '/login' route.
import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router-dom";
<Route path="login" element={user ? <Navigate to="/"/> : <Login />} /> {/* If user is logged in, then redirect to home page, else go to login page */}
Redirecting users if logged in, necessarily does not need a navigation, you could simply just specify the element you want to reach eg:
<Route exact path="/" element={user ? <Home/> : <Login />}/>
Edit:
This is also a possible solution, drawback is that you cant redirect properly. You just have to make sure that you have the fallbackroutes set up right.
{isSignedIn && <Route path="" element={} />}
I would recommend using an AuthRout to wrap your Routes.
function AuthRoute ({children}) {
if(!user.isSignedIn){
//Not signed in
return <Navigate to="/signIn" />
}
//Signed in
return children
}
//Route itself
<Route path="/abc" element={<AuthRoute><YourComponent /></AuthRoute>} />
That way the user gets redirected if he is not signed in
sorry for the that problem, but you can use useNavigate from react-router-dom v6
as below
import { useNavigate } from 'react-router-dom';
export const MyComponent = ({user}) => {
const navigate = useNavigate();
useEffect(() => {
if(user){
navigate('/dashboard')
}else{
navigate('/login')
}
......
},[])
.....
}
and use that codes on your route logic, it makes your route more clean
<Router>
<Routes>
<Route path="/" element={<Home/>} />
<Route path="/products/:category" element={<ProductList/>} />
<Route path="/product/:id" element={<Product/>} />
<Route path="/cart" element={<Cart/>} />
<Route path="/dang-ky" element={<Register/>} />
<Route path="/dang-nhap" element={<MyComponent user = {user} />}/>
<Route path="*" element={<ErrorPage/>} />
</Routes>
</Router>
I have a simple question. What is the best way to use a navbar with multiple components using react router? Just let me show the code so you can understand what I'm trying to say.
import React from "react";
import "./App.css";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect
} from "react-router-dom";
import Auth from "./website/Auth/Auth";
import SocialMedia from "./website/SocialMedia/SocialMedia";
import SingleUser from "./website/SingleUser/SingleUser";
import Search from "./website/Search/Search";
import SinglePhoto from "./website/SinglePhoto/SinglePhoto";
import Navbar from "./components/Navbar/Navbar";
function App() {
const logIn = JSON.parse(localStorage.getItem("token"));
return (
<Router>
<Switch>
<Route exact path="/" component={Auth}>
{logIn ? <Redirect to={`/profile/${logIn.data.id}`} /> : <Auth />}
</Route>
<Navbar>
<Route exact path="/profile/:id" component={SingleUser} />
<Route exact path="/socialmedia" component={SocialMedia} />
<Route exact path="socialmedia/search" component={Search} />
<Route exact path="socialmedia/photo/:id" component={SinglePhoto} />
</Navbar>
</Switch>
</Router>
);
}
export default App;
So I have to reuse my Navbar component, and I tried to use <Navbar />, then the other routes below, but that wasn't working, and when I put <Navbar> </Navbar> that worked and the other components will appear, but is that the way I reuse my Navbar component?
Thanks for your time !!
import React from "react";
import "./App.css";
import {
BrowserRouter as Router,
Switch,
Route,
Redirect
} from "react-router-dom";
import Auth from "./website/Auth/Auth";
import SocialMedia from "./website/SocialMedia/SocialMedia";
import SingleUser from "./website/SingleUser/SingleUser";
import Search from "./website/Search/Search";
import SinglePhoto from "./website/SinglePhoto/SinglePhoto";
import Navbar from "./components/Navbar/Navbar";
function App() {
const logIn = JSON.parse(localStorage.getItem("token"));
return (
<Router>
<Switch>
<Route exact path="/" component={Auth}>
{logIn ? <Redirect to={`/profile/${logIn.data.id}`} /> : <Auth />}
</Route>
<Route Component={Navbar}>
<Route exact path="/profile/:id" component={SingleUser} />
<Route exact path="/socialmedia" component={SocialMedia} />
<Route exact path="socialmedia/search" component={Search} />
<Route exact path="socialmedia/photo/:id" component={SinglePhoto} />
</Route>
</Switch>
</Router>
);
}
export default App;
Try this!
If you want the Navbar to render only on certain routes then render it only on certain routes. Render the Navbar into a route outside the Switch and specify all the paths you want it to be rendered on in an array on the path prop.
Additional notes:
Within the Switch component, order and path specificity matter, reorder your routes to specify more specific paths before less specific paths. This allows you to not need to specify the exact prop for every route.
Don't specify both a component prop and render children on a single Route, see Route render methods. Just render the Redirect or Auth component as children.
Code:
function App() {
const logIn = JSON.parse(localStorage.getItem("token"));
return (
<Router>
<Route
path={["/profile", "/socialmedia"]}
component={Navbar}
/>
<Switch>
<Route path="/profile/:id" component={SingleUser} />
<Route path="socialmedia/photo/:id" component={SinglePhoto} />
<Route path="socialmedia/search" component={Search} />
<Route path="/socialmedia" component={SocialMedia} />
<Route path="/">
{logIn ? <Redirect to={`/profile/${logIn.data.id}`} /> : <Auth />}
</Route>
</Switch>
</Router>
);
}
I am new to React and getting familiarize with React Router. I divided the application into 2 main route since each use a different style: the Splash path is when the user first enter which contain the Splashscreen, Login and Register page; the Menu path is shown after the user is logined. Currently I am working on the Splash route but stumble on a few problem. The Splashscreen contain 1 button that go to the Login Screen. When I click on the button it worked fined, but if I refresh the login page, go back to the Spashscreen and forward, or manually enter the address, the page turn out blank. I tried using HashRouter and it worked, but some suggested that it should only be used on Dev server and not production. I don't use Webpack so I cannot make historyApiFallback: true and the application is running on localhost.
Below are my current code:
App.js:
import React from 'react';
import './App.css';
import SplashTemplate from './component/Template/SplashTemplate';
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
function App() {
return (
<Router>
<div className="App">
<Switch>
<Route path="/" exact={true}>
<SplashTemplate/>
</Route>
</Switch>
</div>
</Router>
);
}
export default App;
SplashTemplate.js:
import React from 'react';
import Splash from '../Splash/Splash';
import LoginForm from '../LoginForm/LoginForm';
import RegistrationForm from '../RegistrationForm/RegistrationForm';
import '../Template/SplashTemplate.css';
import { BrowserRouter, Route, Switch } from "react-router-dom";
function SplashTemplate() {
return(
<div className="background">
<BrowserRouter>
<Switch>
<Route exact path="/" component={Splash} />
<Route path="/login" component={LoginForm} />
<Route path="/register" component={RegistrationForm}/>
</Switch>
</BrowserRouter>
</div>
);
}
export default SplashTemplate;
Splash.js:
import React from 'react';
import {
BrowserRouter as Router,
Link
} from "react-router-dom";
function Splash() {
return(
<div className="container">
<Link to="/login">
<button className="splashButton">Login</button>
</Link>
</div>
);
}
export default Splash;
Anyone can suggest a solution? I have try the above mention but still not the answer I am looking for.
Update
Thanks to Danilo Venticinque answer I have reformatted the App.js file to:
function App() {
return (
<Router>
<div className="App">
<Switch>
<SplashTemplate>
<Route exact path="/" component={Splash}/>
<Route path="/login" component={LoginForm}/>
<Route path="/register" component={RegistrationForm}/>
</SplashTemplate>
<MainTemplate>
<Route path="/mainmenu" component={MainMenu}/>
</MainTemplate>
</Switch>
</div>
</Router>
);
}
And changed the SplashTemplate.js to:
class SplashTemplate extends Component {
render(){
return(
<div className="background">{this.props.children}</div>
);
};
}
It seem to work for the Splash path but now the problem show up in the Menu path where if the route is input manually (http://localhost:3000/mainmenu) the template for the Menu did not show up but instead the Splash template did. What am I doing wrong here?
Your problem is in the App.js routing. It's rendering the SplashTemplate component (which contains the other routes) only when the exact path is /. So, if you launch the page with /login, SplashTemplate doesn't get rendered (actually, nothing does) and there's no router to serve your other routes.
I would suggest moving the routes into a single component or changing the App.js routing logic so that it would still display SplashTemplate for /login and other desired routes.
So after digging around and following both React Router V4 Routers with Master Pages / Templates and React Router v5.0 Nested Routes I was able to come up with a solution. First, move all the Routing to a seperate file call Route.js and import it to App.js. Since we need to seperate the two path we will put the routing in 2 different functions and call them in a main function like below:
Route.js
...
function LayoutRoute() {
return (
<Switch>
<Route path="/splash" component={SplashLayout} />
<Route path="/main" component={MainLayout} />
<Route path="/" component={NotFound} />
</Switch>
);
}
function SplashLayout() {
return (
<SplashTemplate>
<Route path="/splash/splash" exact component={Splash} />
<Route path="/splash/login" exact component={LoginForm} />
<Route path="/splash/register" exact component={RegistrationForm} />
<Redirect from="/splash" to="/splash/splash" exact />
<Route />
</SplashTemplate>
);
}
function MainLayout() {
return (
<MainTemplate>
<Route path="/main/menu" exact component={MainMenu} />
<Redirect from="/main" to="/main/menu" exact />
<Route />
</MainTemplate>
);
}
const NotFound = () => <h1>Not Found</h1>;
export default LayoutRoute;
The App.js can just call Route:
function App() {
return (
<Router>
<LayoutRoute></LayoutRoute>
</Router>
);
}
And the Template file:
SplashTemplate.js
class SplashTemplate extends Component {
render(){
return(
<div className="background">{this.props.children}</div>
);
};
}
This can help achive seperated Layout for each path of the website/app needed and make sure the page is rendered when entered manually or refresh.
Im trying to figure out how to get my navigation bar setup as most of the UI is coming together. I have setup my index.js and also a Route.js and then linked them with my different components like so:
Index.js
import React from "react";
import ReactDOM from "react-dom";
import { Auth0Provider } from "./react-auth0-spa.js";
import { useAuth0 } from "./react-auth0-spa";
import Routes from "./Routes"
import config from "./utils/auth_config.json";
import { BrowserRouter } from "react-router-dom";
// A function that routes the user to the right place
// after login
const onRedirectCallback = appState => {
history.push(
appState && appState.targetUrl
? appState.targetUrl
: window.location.pathname
);
};
ReactDOM.render(
<Auth0Provider
domain={config.domain}
client_id={config.clientId}
redirect_uri={window.location.origin}
onRedirectCallback={onRedirectCallback}
>
<BrowserRouter>
<Routes />
</BrowserRouter>
</Auth0Provider>,
document.getElementById("root")
);
Routes.js
import React, { Component } from "react";
import { Router, Route, Switch, BrowserRouter } from "react-router-dom";
import {Link } from "react-router-dom";
import Profile from "./components/user/Profile";
import PrivateRoute from "./components/user/PrivateRoute";
import history from "./utils/history.js";
import HomePage from "./modules/HomePage.js";
import ProductPage from "./modules/ProductPage";
class Routes extends Component {
render() {
return (
<Router history={history}>
<Switch>
<Route path="/" component={HomePage} />
<Route path="/ProductPage" component={ProductPage} />
<PrivateRoute path="/profile" component={Profile} />
</Switch>
</Router>
)
}
}
export default Routes;
but when i reload my site it just continues to say localhost:8080/ProductPage like its suppose to be the default, then when i manually enter localhost:8080/ and click on a button after linking it with
<Link to="ProductPage">
it will show on the tab localhost:8080/ProductPage but wont actually redirect me to the other component, i am just wondering what i am doing wrong?
Issue
You have your "home" route listed first in the Switch.
Switch
Renders the first child <Route> or <Redirect> that matches the location.
"/" is less specific and matches basically all routes, so even though the URL is "/ProductPage", "/" still matches it and HomePage is rendered.
Solution
Either move it after the other more specific routes or use the exact prop on it.
<Router history={history}>
<Switch>
<Route path="/ProductPage" component={ProductPage} />
<PrivateRoute path="/profile" component={Profile} />
<Route path="/" component={HomePage} />
</Switch>
</Router>
or
<Router history={history}>
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/ProductPage" component={ProductPage} />
<PrivateRoute path="/profile" component={Profile} />
</Switch>
</Router>