I was looking for the simplest way to render the same component but from different paths.
I have the following so that both "/" and "/login" render the Login component.
import React from "react";
import { Route, Switch, Redirect } from 'react-router-dom';
import './App.scss';
import Login from "../../login/Login";
const App = () => {
return (
<div className="App">
<div className="App-container">
<Switch>
<Route exact path={["/", "/login"]} component={() =>
<Login login={true} />}/>
<Redirect to="/" />
</Switch>
</div>
</div>
);
}
export default App;
This does appear to work, however, it returns an error in the console.
Warning: Failed prop type: Invalid prop 'path' of type 'array' supplied to 'Route', expected 'string'.
I'm trying to do this...
<Route exact path={"/"} component={() => <Login login={true} />}/>
<Route exact path={"/login"} component={() => <Login login={true} />}/>
But with a shorter method, is this possible with react-router-dom? Any help would be greatly appreciated
You could create an array that contains the paths / and /login and use map on that array to render the same thing for both paths.
<Switch>
{["/", "/login"].map(path => (
<Route
key={path}
exact
path={path}
render={() => <Login login={true} />}
/>
))}
<Redirect to="/" />
</Switch>
If you wish to render the same component on the several routes, you can do this by specifying your path as a regular expression
lets say you want to display 'Home' component for 'Home', 'User' and 'Contact' components then here is code.
<Route path="/(home|users|contact)/" component={Home} />
Related
Here is mycode of the file PrivateRoute.js
import React from "react";
import {Route,Redirect} from "react-router-dom"
import {isAuthenticated} from "./index"
const PrivateRoutes = (props)=>{
return(
isAuthenticated()?(<Route
render={ (props) =>
<component {...props}/>} />):
(<Redirect to={{ pathname:"/signin"}}/>)
// <h1>hey there</h1>
)
}
export default PrivateRoutes;
In this code it is saying that value of props is read but never used but iam using it in render function,destructuring is also not working here.
Here isAuthenticated() is my boolean function . If it evaluates to true i want to get on more route to user dashboard.
This is how my routes.js file looks like
import React from 'react'
import {BrowserRouter,Route,Switch} from "react-router-dom";
import AdminRoutes from './auth/helper/AdminRoutes';
import PrivateRoutes from './auth/helper/PrivateRoutes';
import Home from './core/Home';
import AdminDashboard from './user/AdminDashBoard';
import Signin from './user/Signin';
import Signup from './user/Signup';
import UserDashboard from './user/UserDashBoard';
function Routes() {
return (
<BrowserRouter>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path="/signup" component={Signup} />
<Route exact path="/signin" component={Signin} />
<PrivateRoutes component="UserDashboard" exact path="/user/dashboard"/>
<AdminRoutes exact path="/admin/dashboard" component={AdminDashboard}/>
</Switch>
</BrowserRouter>
)
}
export default Routes
Help me to solve this problem.
This is because you have declared *two functions, each taking a props object argument, but only the inner/nested function's props is referenced.
Rename the nested props to something else like routeProps and spread both to the rendered component. Remember also that valid React component names are PascalCased.
Example:
const PrivateRoutes = ({ component: Component, ...props }) => {
return isAuthenticated()
? (
<Route
render={(routeProps) => (
<Component {...props} {...routeProps} />
)}
/>
) : <Redirect to={{ pathname:"/signin"}}/>;
}
Then also fix the PrivateRoutes component use to pass a value React component reference instead of a string.
<Switch>
<Route path="/signup" component={Signup} />
<Route path="/signin" component={Signin} />
<PrivateRoutes component={UserDashboard} path="/user/dashboard" />
<AdminRoutes path="/admin/dashboard" component={AdminDashboard} />
<Route path='/' component={Home} />
</Switch>
I'm attempting to create a few routes on my web app using react-router. However, some pages need to share components - such as the Navigation or Footer - where others do not.
What I essentially need is a way to check if a path doesn't match a few preset locations, and if it doesn't then render the content.
At the moment I'm doing this like so:
const displayComponentIfAllowed = (location, component) => {
const C = component;
const globalComponentsDisallowedPaths = ["/booking"];
// If the path matches something within the blocked list, then return null.
let allowToRender = true;
globalComponentsDisallowedPaths.forEach(disallowedPath => {
if(location.pathname === disallowedPath){
allowToRender = false;
}
});
// Otherwise, return component to render.
return allowToRender ? <C /> : null;
}
return (
<Router>
<Routes>
<Route render={({ location }) => displayComponentIfAllowed(location, Navigation)} />
<Route path="/">
<Route index element={<Home />} />
<Route path="booking/:customer_id" element={<Booking />} />
</Route>
<Route render={({ location }) => displayComponentIfAllowed(location, Footer)} />
</Routes>
</Router>
);
However, ever since V6 of react-router-dom has been introduced, this doesn't seem to work. I imagine this is because the render prop has been deprecated (although I'm unsure, but there's no mention of it in the docs).
Are there any workarounds - or a better implementation of this which works with V6? Cheers
Create a layout component that renders the UI components you want and an Outlet for nested routes to be rendered into.
Example:
import { Outlet } from 'react-router-dom';
const HeaderFooterLayout = () => (
<>
<Navigation />
<Outlet />
<Footer />
</>
);
...
import {
BrowserRouter as Router,
Routes,
Route
} from "react-router-dom";
...
<Router>
<Routes>
<Route element={<HeaderFooterLayout />} >
<Route path="/">
<Route index element={<Home />} />
... other routes you want to render with header/footer ...
</Route>
</Route>
<Route path="booking/:customer_id" element={<Booking />} />
... other routes you want to not render with header/footer ...
</Routes>
</Router>
So I'm learning React and building an app with multiple pages, I made a Routes file which looks like this:
import 'swiper/swiper.min.css';
import React from "react";
import { Route, Routes } from "react-router-dom";
import Home from "../pages/Home";
import Catalog from "../pages/Catalog";
import Detail from "../pages/Detail";
const Router = () => {
return (
<Routes>
<Route
path='/:category/search/:keyword'
component={Catalog}
/>
<Route
path='/:category/:id'
component={Detail}
/>
<Route
path='/:category'
component={Catalog}
/>
<Route
path='/'
exact
component={Home}
/>
</Routes>
);
}
And App.js looks like this:
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Header from './components/header/Header';
import Footer from './components/footer/Footer';
import Router from './config/Router';
function App() {
return (
<BrowserRouter>
<Routes>
<Route render={props =>{
<>
<Header {...props}/>
<Router/>
<Footer/>
</>
}}/>
</Routes>
</BrowserRouter>
);
}
export default App;
As you see, I have a browser router and Route which passes props to a component(as I understood) but for some reason the components don't display on the page(original components just have with their name inside of them, but they don't display in App.js).
And my console also says:
No routes matched location "/"
In routes.jsx file. I'm guessing it should lead to main page, but for some reason the route doesn't match and components in App.js don't display.
In Version 6.0.0 there is not any component prop in Route. It has been changed to element. So you need to change your Router to :
const Router = () => {
return (
<Routes>
<Route
path='/:category/search/:keyword'
element={Catalog}
/>
<Route
path='/:category/:id'
element={Detail}
/>
<Route
path='/:category'
element={Catalog}
/>
<Route
path='/'
exact
element={Home}
/>
</Routes>
);
}
As you've said you're using react-router-dom 6.0.2, and it seems that the tutorial you are following is for the older version (5?). There were some breaking changes in version 6.
You need to change your Router component to use element instead of component:
const Router = () => {
return (
<Routes>
<Route path="/:category/search/:keyword" element={<Catalog />} />
<Route path="/:category/:id" element={<Detail />} />
<Route path="/:category" element={<Catalog />} />
<Route path="/" exact element={<Home />} />
</Routes>
);
};
and also your App component seems to be getting in the way with the nested route.
I think it can be simplified to:
function App() {
return (
<BrowserRouter>
<>
<Header />
<Router />
<Footer />
</>
</BrowserRouter>
);
}
You can see a working demo on stackblitz
I created this react component which has some nested routes. The problem is that the nested page component is either not rendering at all despite the URL changes or just returns a blank page.
I tried the suggestions from other posts like adding/removing exact in the parent route, but it's still not working.
Below are my codes:
// the parent component
<div className="App">
<Router>
<Navbar />
<Switch>
<Route exact path="/" render={() => <MyPage accessToken={accessToken} />}/>
<Route path="/editing/:playlistId" render={(props) =>
<EditingPlaylist {...props} accessToken={accessToken} />} />
</Switch>
</Router>
</div>
//the child component EditingPlaylist
render() {
const { pathname } = this.props.location;
return (
<div className="editing">
<Switch>
<Route exact path={pathname} render={() =>
<Searchbar accessToken={this.props.accessToken} />} />
<Route path={`${pathname}/test`} component={<p>Test</p>} />
<Route path={`${pathname}/album/:albumId`} render={
(props) => <AlbumPage {...props} accessToken={this.state.accessToken} />} />
<Route path={`${pathname}/artist/:artistId`} render={
(props) => <ArtistProfile {...props} accessToken={this.state.accessToken} />} />
</Switch>
</div>)
}
export default withRouter(EditingPlaylist);
Use url and path:
const { url, path } = this.props.match
to defined nested routes.
So, in nested routes:
<Switch>
<Route
exact
path={path} // HERE
render={() => <Searchbar accessToken={this.props.accessToken} />}
/>
...
</Switch>
There is a difference between url and path:
url: It is what is visible in the browser. e.g. /editing/123. This should be used in when redirecting via Link or history.push
path: It is what matched by the Route. e.g. /editing/:playlistId. This should be used when defining (nested) paths using Route.
From docs:
path - (string) The path pattern used to match. Useful for building nested <Route>s
url - (string) The matched portion of the URL. Useful for building nested <Link>s
I want to test if the routes exist in the component. App should render the specific component on the specific path.
App.js
return (
<Router>
<Header jsTrendingTopics={this.props.data} />
<Switch>
<Route exact path="/" render={() => <Dashboard jsTrendingTopics={this.props.data} />} />
<Route exact
path="/language/:languagename"
render={(props) => this.handleTopic(props)
}
/>
</Switch>
</Router>
)
}
I expect the test to return the component that should render on that specific route.
I think MemoryRouter with initialEntries={['/]} is what you are looking for.
import Dashboard from ...
jest.mock('path to Dashboard component');
Dashboard.mockImplementationOnce(() => <div>Dashboard</div>);
render(
<MemoryRouter initialEntries={['/']}>
<App/>
</MemoryRouter>
);
expect(screen.getByText("Dashboard").toBeInTheDocument()
You can read this document for more examples
https://javascript.plainenglish.io/testing-react-router-with-jest-bc13d367bad