i want to use that Hashrouter, but when i try, i got this error:
<Router basename="/admin"> is not able to match the URL "/" because it does not start with the basename, so the <Router> won't render anything.
i put "Homepage": "./admin" in packedjson
but when i use BrowserRouter, its render normaly, can anyone explain why, please?
The code i'm using to try to understand router v6:
import "./styles.css";
import {
BrowserRouter,
Routes,
Route,
Navigate,
Outlet,
Link,
HashRouter,
} from "react-router-dom";
const ProtectedRoutes = () => <Outlet />;
const Configuration = () => <h1>Configuration</h1>;
const SummaryPage = () => <h1>SummaryPage</h1>;
const Dashboard = () => <h1>Dashboard</h1>;
const Appointments = () => <h1>Appointments</h1>;
const NotFound = () => <h1>NotFound</h1>;
export default function App() {
return (
<HashRouter basename="/admin">
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Link to="/dashboard" className="link">
Home
</Link>
</div>
<Routes>
<Route path="/configuration/configure" element={<Configuration />} />
<Route path="/configuration" element={<SummaryPage />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/appointments" element={<Appointments />} />
<Route path="/" element={<Navigate replace to="/configuration" />} />
<Route path="*" element={<NotFound />} />
</Routes>
</HashRouter>
);
}
There mostly seems to be a misunderstanding with how the basename prop is applied in the router, specifically the HashRouter. With the HashRouter the basename prop is a value that is applied against the paths the app is handling, not against the domain path where the app is served/running.
Example:
<HashRouter basename="/admin">
<Link to="/dashboard" className="link"> // renders <a href="#/admin/dashboard">
Dashboard
</Link>
...
<Routes>
<Route path="/configuration">
<Route path="configure" element={<Configuration />} />
<Route index element={<SummaryPage />} />
</Route>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/appointments" element={<Appointments />} />
<Route path="/" element={<Navigate replace to="/configuration" />} />
<Route path="*" element={<NotFound />} />
</Routes>
</HashRouter>
In other words, the basename prop value is applied to the URL hash and not the URL path, i.e. it's applied to everything after the hash.
mysite.com/someSubdomain/#/admin /something / ... more nested paths
|--domain-|--subdomain--|#|--------------hash-----------------|
| | | |basename| app path | ... app subpaths
If you are wanting the "/admin" to show up prior to the hash, then this is part of where the entire app is deployed to and served up from. In this case the app needs to be deployed to mysite.com in a "/admin" subdirectory. You also won't need to specify the basename="/admin" if you don't want an additional "/admin" to show up in the app's routing.
mysite.com/admin/#/something
...
<HashRouter>
<Link to="/dashboard" className="link"> // renders <a href="#/dashboard">
Dashboard
</Link>
...
<Routes>
<Route path="/configuration">
<Route path="configure" element={<Configuration />} />
<Route index element={<SummaryPage />} />
</Route>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/appointments" element={<Appointments />} />
<Route path="/" element={<Navigate replace to="/configuration" />} />
<Route path="*" element={<NotFound />} />
</Routes>
</HashRouter>
update: Not a solution =[ basename not works in Routes, and hashrouter not working with basename
Some solution here:
https://github.com/remix-run/react-router/issues/7128#issuecomment-582591472
but i don't know if it's the best one.
// url where new router is created: https://my-site/who/users
const RootModule = () => {
return (
<main>
<BrowserRouter>
<Routes basename="who/users">
<nav>
<Link to="">Home</Link>
<Link to="who/users/about">About</Link>
<Link to="who/users/users">Users</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="who/users/about" element={<About />} />
<Route path="who/users/users" element={<Users />} />
</Routes>
</Routes>
</BrowserRouter>
</main>
);
};
and here working
SANDBOX
Related
My React app is giving me the error No routes matched location "/"
My App.js looks like:
import Form from './components/Form';
import NavMenu from './components/NavMenu';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
function App() {
// Irrelevant code
return (
<Router>
<div>
<NavMenu />
<Routes>
<Route path="/:nav_string" element={<Form />}></Route>
</Routes>
</div>
</Router>
);
}
export default App;
Any thoughts why this is happening?
I got rid of the error, although it's not a clean solution. I created a new component Home.js, added it to App.js with a route of "/" :
return (
<Router>
<div className="content">
<NavMenu response={response}/>
<Routes>
<Route path="/" element={<Home />}></Route> // Added home element
<Route path="/:nav_string" element={<Form response={response} />}></Route>
</Routes>
</div>
</Router>
);
Although I'm not a big fan of this solution because Home.js returns null. I just created it to get rid of this warning. What can someone do if they don't actually need a route with a path matching / ?
If you don't really need to render anything on the "/" path you could render a redirect to the form's route, perhaps with some default value.
Example:
return (
<Router>
<div className="content">
<NavMenu response={response} />
<Routes>
<Route path="/" element={<Navigate to="/someDefaultValue" replace />} />
<Route path="/:nav_string" element={<Form response={response} />} />
</Routes>
</div>
</Router>
);
An alternative could also be to render the Form component on both routes. RRD is optimized such that the Form component remains mounted while navigating between the routes or while the nav_string param value changes.
Example:
return (
<Router>
<div className="content">
<NavMenu response={response} />
<Routes>
<Route path="/" element={<Form response={response} />} />
<Route path="/:nav_string" element={<Form response={response} />} />
</Routes>
</div>
</Router>
);
Just make sure that Form can handle a potentially undefined nav_string param value. You could provide a fallback value.
const { nav_string = "someDefaultValue" } = useParams();
And then there is always the "catch all" route where you can render some fallback UI for any "unhandled" routes. This would include "/".
Example:
return (
<Router>
<div className="content">
<NavMenu response={response} />
<Routes>
<Route path="*" element={<NotFound />} />
<Route path="/:nav_string" element={<Form response={response} />} />
</Routes>
</div>
</Router>
);
You can add 404 route
Page not found will be displayed when no route matches the url
return (
<Router>
<div className="content">
<NavMenu response={response}/>
<Routes>
<Route path="/:nav_string" element={<Form response={response} />}></Route>
<Route path='*' element={<NotFound />} /> {/* You can change NotFound element*/}
</Routes>
</div>
</Router>
);
This should help:
<BrowserRouter>
<NavMenu/>
<Routes>
<Route path="/" element={<Form/>}></Route>
<Routes/>
<BrowserRouter/>
the format for "/:nav_string" is a path parameter, there is no "/" path
try type in for example "/Product", then it solved
function App() {
return (
<RecoilRoot>
<Router>
<Navbar />
<Routes>
<Route path={"/"} element={<Home />} />
<Route path={`/page/:menu`} element={<MovieMenu />} />
<Route path={`/movie/:id`} element={<Detail />} />
<Route path={`/search/:searchText`} element={<Search />} />
<Route path={"*"} element={<NotFound />} />
</Routes>
</Router>
</RecoilRoot>
);
}
If i process 404 page in the above way, / handle it well, but <NotFound /> not be rendered if any path is entered after /page/fldlfsd;lf; or /search/dsklfskldf. Is there a way?
Paths like "/page/fldlfsd;lf;" and "/search/dsklfskldf" will be matched and rendered by the Routes component. The route param validation needs to occur in the routed component.
Each component can use the useParams hook to access the route param, validate it, and redirect to the NotFound route if param is invalid.
To help with this I suggest creating a discrete route to render NotFound so you can imperatively redirect to it from components and create a redirect route to handle unknown routes.
Example:
function App() {
return (
<RecoilRoot>
<Router>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/page/:menu" element={<MovieMenu />} />
<Route path="/movie/:id" element={<Detail />} />
<Route path="/search/:searchText" element={<Search />} />
<Route path="/404" element={<NotFound />} />
<Route path="*" element={<Navigate to="/404" replace />} />
</Routes>
</Router>
</RecoilRoot>
);
}
...
MovieMenu
const navigate = useNavigate();
const { menu } = useParams();
useEffect(() => {
... logic to validate menu param ...
if (invalidMenu) {
navigate("/404", { replace: true });
}
}, [menu, navigate]);
...
I am using use location to hide the navbar if the pathname name is /admin, /employee, /publisher. but I got an error saying that Error: useLocation() may be used only in the context of a <Router> component.
This is My App.js
import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
function App() {
const location = useLocation()
return (
<>
<UserState>
<Router>
{!["/admin", "/employee", "/publisher"].includes(location.pathname) && <Navbar/>} //For to hide the navbar if the pathname is /admin, /employee, /publisher
<Routes onUpdate={() => window.scrollTo(0, 0)}>
<Route exact path="/" element={<Home />} />
<Route exact path="/service" element={<Service />} />
<Route exact path="/contact" element={<Contact />} />
<Route exact path="/login" element={<Login />} />
<Route exact path="/reset" element={<Reset />} />
<Route exact path="/reset/:token" element={<Newpassword />} />
<Route path="*" element={<NoteFound/>} />
{/* admin pages */}
<Route path="/admin" element={<Admin />}>
<Route path="add-project" element={<Addproject />} />
<Route path="all-user" element={<AllUser />} />
</Route>
{/* Publisher dasboard */}
<Route path="/publisher" element={<Publisher />}>
<Route path="project-status" element={<ProjectStatus />} />
<Route path="allpublise" element={<Allpublise />} />
</Route>
</Route>
</Routes>
</Router>
</UserState>
</>
);
}
export default App;
The useLocation hook (and all other react-router-dom hooks) need a router above it in the ReactTree so that a routing context is available.
2 options:
Move the Router component up the tree and wrap the App component so it can use the useLocation hook.
import { BrowserRouter as Router } from 'react-router-dom';
...
<Router>
<App />
</Router>
...
import { Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
function App() {
const location = useLocation();
return (
<UserState>
{!["/admin", "/employee", "/publisher"].includes(location.pathname) && <Navbar/>}
<Routes onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/" element={<Home />} />
<Route path="/service" element={<Service />} />
<Route path="/contact" element={<Contact />} />
<Route path="/login" element={<Login />} />
<Route path="/reset" element={<Reset />} />
<Route path="/reset/:token" element={<Newpassword />} />
<Route path="*" element={<NoteFound/>} />
{/* admin pages */}
<Route path="/admin" element={<Admin />}>
<Route path="add-project" element={<Addproject />} />
<Route path="all-user" element={<AllUser />} />
</Route>
{/* Publisher dasboard */}
<Route path="/publisher" element={<Publisher />}>
<Route path="project-status" element={<ProjectStatus />} />
<Route path="allpublise" element={<Allpublise />} />
</Route>
</Routes>
</UserState>
);
}
export default App;
Move the useLocation hook down the tree so that it's used within the Router component.
import { Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
function App() {
return (
<UserState>
<Router>
<Navbar/>
<Routes onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/" element={<Home />} />
<Route path="/service" element={<Service />} />
<Route path="/contact" element={<Contact />} />
<Route path="/login" element={<Login />} />
<Route path="/reset" element={<Reset />} />
<Route path="/reset/:token" element={<Newpassword />} />
<Route path="*" element={<NoteFound/>} />
{/* admin pages */}
<Route path="/admin" element={<Admin />}>
<Route path="add-project" element={<Addproject />} />
<Route path="all-user" element={<AllUser />} />
</Route>
{/* Publisher dasboard */}
<Route path="/publisher" element={<Publisher />}>
<Route path="project-status" element={<ProjectStatus />} />
<Route path="allpublise" element={<Allpublise />} />
</Route>
</Routes>
</Router>
</UserState>
);
}
export default App;
...
const Navbar = () => {
const location = useLocation();
return !["/admin", "/employee", "/publisher"].includes(location.pathname)
? /* Return navbar JSX here */
: null;
};
useLocation() hook is used to extract the current location from the router.
For this purpose it's need the router context to pass the Location content
So if you want to use this hook, you need to use it in one of the nested components in <Router> Provider.
For your situation, you need to move the hook into the navbar component.
import { useLocation } from 'react-router-dom';
function Navbar() {
const location = useLocation()
if(["/admin", "/employee", "/publisher"].includes(location.pathname))
return <></>
return (
<>
I'm a navbar
</>
);
}
export default Navbar;
I am a beginner with react-router-dom, there are two different states in the code when I dont use Navigate from react-router-dom , it works properly , but when I use the Navigate function it renders a blank page.
I have confirmed that all the individual components work and render properly.
Please help me solve this issue .
Here is my code of App.js without Navigate
import React from 'react';
import { Container } from '#material-ui/core';
import { BrowserRouter , Route , Routes , Navigate } from 'react-router-dom'
import PostDetails from './components/PostDetails/PostDetails';
import Home from './components/Home/Home';
import Navbar from './components/Navbar/Navbar';
import Auth from './components/Auth/Auth';
const App = () => {
const user = JSON.parse(localStorage.getItem('profile'));
return (
<BrowserRouter>
<Container maxWidth="lg">
<Navbar />
<Routes>
<Route exact path="/" element ={<Home/>} />
<Route path="/auth" element={<Auth/>} />
<Route path="/posts" exact element={<Home/>} />
<Route path="/posts/search" exact element={<Home/>} />
<Route path="/posts/:id" exact element={<PostDetails/>} />
<Route path="/auth" exact element={() => (!user ? <Auth /> : <Navigate to="/posts" />)} />
</Routes>
</Container>
</BrowserRouter>
)
};
export default App;
Here is my code of App.js with Navigate which does not works
import React from 'react';
import { Container } from '#material-ui/core';
import { BrowserRouter , Route , Routes , Navigate } from 'react-router-dom'
import PostDetails from './components/PostDetails/PostDetails';
import Home from './components/Home/Home';
import Navbar from './components/Navbar/Navbar';
import Auth from './components/Auth/Auth';
const App = () => {
const user = JSON.parse(localStorage.getItem('profile'));
return (
<BrowserRouter>
<Container maxWidth="lg">
<Navbar />
<Routes>
<Route path="/" exact component={() => <Navigate replace to="/posts" />} />
<Route path="/posts" exact element={<Home/>} />
<Route path="/posts/search" exact element={<Home/>} />
<Route path="/posts/:id" exact element={<PostDetails/>} />
<Route path="/auth" exact element={() => (!user ? <Auth /> : <Navigate replace to="/posts" />)} />
</Routes>
</Container>
</BrowserRouter>
)
};
export default App;
In react-router-dom#6 the Route components's element prop takes only a ReactNode, a.k.a. JSX. You've one route taking a component prop which is invalid, and two routes passing a function.
Use the element prop and pass JSX only.
Note that there is also no longer any exact prop, in RRDv6 all routes are always exactly matched.
<BrowserRouter>
<Container maxWidth="lg">
<Navbar />
<Routes>
<Route path="/" element={<Navigate replace to="/posts" />} />
<Route path="/posts" element={<Home />} />
<Route path="/posts/search" element={<Home />} />
<Route path="/posts/:id" element={<PostDetails />} />
<Route
path="/auth"
element={!user ? <Auth /> : <Navigate replace to="/posts" />}
/>
</Routes>
</Container>
</BrowserRouter>
If you are trying to protect these "/posts*" routes then it is common to create a layout route to handle redirecting to the login route or render the protected routes.
Example:
const AuthLayout = ({ authenticated }) =>
authenticated
? <Outlet />
: <Navigate to="/auth" replace />;
...
<BrowserRouter>
<Container maxWidth="lg">
<Navbar />
<Routes>
<Route element={<AuthLayout authenticated={!!user} />}>
<Route path="/posts" element={<Home />} />
<Route path="/posts/search" element={<Home />} />
<Route path="/posts/:id" element={<PostDetails />} />
</Route>
<Route path="/" element={<Navigate replace to="/posts" />} />
<Route
path="/auth"
element={!user ? <Auth /> : <Navigate replace to="/posts" />}
/>
</Routes>
</Container>
</BrowserRouter>
use element props instead component
<Route path="/" exact component={() => <Navigate replace to="/posts" />} />
<Route path="/" exact element={() => <Navigate replace to="/posts" />
I have a React site with three different routes, and I want it to automatically display the first one, which is called Home, when a user enters the site. Here is the code I have in App.js:
<Router>
<Navigation />
<Switch>
<Route path="/hypstats" exact component={() => <Home />} />
<Route path="/hypstats/auctions" exact component={() => <AuctionViewer />} />
<Route path="/hypstats/bazaar" exact component={() => <BazaarViewer />} />
</Switch>
</Router>
And here is the Navigation component:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import "../App.css"
function Navigation(props) {
return (
<div className="navbar">
<Link className="navlink" to="/hypstats">HypStats</Link>
<Link className="navlink" to="/hypstats/auctions">Auctions</Link>
<Link className="navlink" to="/hypstats/bazaar">Bazaar</Link>
</div>
)
}
export default Navigation;
To make any view as the default view you could include the following into your Navigation
<Route path="/" exact component={() => <Home />} />
Or you could write as below:
<Redirect from="/" to="/hypstats"} />
<Router>
<Navigation />
<Switch>
<Route path="/hypstats" exact component={() => <Home />} />
<Route path="/hypstats/auctions" exact component={() => <AuctionViewer />} />
<Route path="/hypstats/bazaar" exact component={() => <BazaarViewer />} />
**<Route path="/" exact component={() => <Home />} />**
</Switch>
</Router>
We use the basename attribute to tell the basename of the site. So that in the next routes, we would not have to set basename, here /hypstats, manually every time we add a new route. React Router manages it by itself.
<Router basename="/hypstats">
<Navigation />
<Switch>
<Route path="/" exact component={() => <Home />} />
<Route path="/auctions" exact component={() => <AuctionViewer />} />
<Route path="/bazaar" exact component={() => <BazaarViewer />} />
</Switch>
</Router>
Run this somewhere in your App component.
history.push({
pathname: '/hypstats',
});
You are using "react-router-dom" so you can import:
import { useHistory } from "react-router-dom";
And then you can use:
const history = useHistory();
So whenever user enters your react application it will open the '/hypstats'.
You could do this in a useEffect.