React Router Switch not rendering specific component - javascript

I have a React app that is currently using react-router#4.2.0 and I'm struggling with rendering a specific component when the URL changes.
When I try to visit /locations/new it returns with a PropTypes error from the CityList component. I have tried adding in exact to the Route component within LocationsWrapper and then Main config too, however, this then influences other routes - such as /locations to become null.
// BrowserRouter
import React from "react";
import { render } from "react-dom";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import store from "./store";
import Navbar from "./components/Core/Navbar";
import Routes from "./config/routes";
render(
<Provider store={store}>
<BrowserRouter>
<div style={{ backgroundColor: "#FCFCFC" }}>
<Navbar />
<Routes />
</div>
</BrowserRouter>
</Provider>,
document.getElementById("root")
);
// Router config - ( Routes )
import React from "react";
import { Route, Switch } from "react-router-dom";
import Home from "../components/Home";
import Locations from "../components/Locations";
import CityList from "../components/CityList";
import CreateLocation from "../components/CreateLocation";
import Locale from "../components/Locale/index";
import Profile from "../components/Profile";
import NoMatch from "../components/Core/NoMatch";
import requireAuth from "../components/Core/HOC/Auth";
const LocationsWrapper = () => (
<div>
<Route exact path="/locations" component={Locations} />
<Route path="/locations/new" component={CreateLocation} />
<Route path="/locations/:id" component={CityList} />
</div>
);
const Main = () => (
<main>
<Switch>
<Route exact path="/" component={requireAuth(Home)} />
<Route path="/locations" component={LocationsWrapper} />
<Route path="/locale/:id" component={Locale} />
<Route path="/profile" component={requireAuth(Profile, true)} />
<Route component={NoMatch} />
</Switch>
</main>
);
export default Main;
Am I best avoiding <Switch> entirely and implementing a new method for routes that are undefined - such as 404s?

Yes, this will definitely return first
<Route path="/locations/:id" component={CityList} />
In react-router 4 there is no concept of index route, it will check each and every routes so in your defining routes are same
<Route path="/locations/new" component={CreateLocation} />
<Route path="/locations/:id" component={CityList} />
both path are same '/location/new' and '/location/:id' so /new and /:id are same params.
so at last 'CityList' will return
You can define like this
<Route path="/locations/create/new" component={CreateLocation} />
<Route path="/locations/list/:id" component={CityList} />

Pretty sure your route is not working cause you are also matching params with /locations/new with /locations/:id so then 'new' becomes Id param.
Try changing this
<Route path="/locations/new" component={CreateLocation} />
To something like this
<Route path="/locs/new" component={CreateLocation} />
Just a suggestion hope this may help

Related

React Project working but not displaying some components

i am trying to build a portfolio website using react and i am using react-router-dom for navigation.
everything was working for a while then i made a stupid mistake of keeping the project in onedrive and had some trouble.
link to code: https://github.com/Raghav-rv28/portfolio-website
Live: https://raghav-rv28.github.io/portfolio-website/, this is not really helpful as we cannot see anything but you can see the screenshots below,
when i run the project on my local machine it runs :
as you can see the elements are there but they just don't appear to me for some reason.
Some of the Code:
import React from 'react'
import {Route, Routes} from 'react-router-dom'
import Layout from './Components/Layout'
import Home from './Components/Home'
import About from './Components/About'
import Contact from './Components/Contact'
import Interests from './Components/Interests'
import Projects from './Components/Projects'
import './App.scss';
function App() {
return (
<>
<Routes>
<Route path="/" element = { <Layout />} >
<Route index element={< Home/>} />
<Route path='About' element={< About/>} />
<Route path='Contact' element={< Contact/>} />
<Route path='Interests' element={< Interests/>} />
<Route path='Projects' element={< Projects/>} />
</Route>
</Routes>
</>
);
}
export default App;
Layout.js:
import React from 'react';
import './index.scss';
import SideNavbar from '../SideNavbar/index';
import { Outlet } from 'react-router-dom';
export default function Layout(){
return(
<div className="App">
<SideNavbar />
<div className="page">
<Outlet />
</div>
</div>)
}
index.js :
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from 'react-router-dom'
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
You nested your routes for (Home, About, Contact, etc.) inside the "Layout" route. This means that react router will render BOTH "Layout" and whichever component is provided by a matching nested route.
Try restructuring your routes like this:
<>
<Routes>
<Route path="/" element = { <Layout />} />
<Route index element={< Home/>} />
<Route path='About' element={< About/>} />
<Route path='Contact' element={< Contact/>} />
<Route path='Interests' element={< Interests/>} />
<Route path='Projects' element={< Projects/>} />
</Routes>
</>
Turns out my stupid As* forgot to import the animation library i'm using and the opacity for the pages was set to 0.

Error "Error: A <Route> is only ever to be used as the child of <Routes> element"

I am trying to use routing for the first time and followed the exact instructions from Udemy:
File App.js:
import { Route } from "react-router-dom";
import Welcome from "./Pages/Welcome";
import Game from "./Pages/Game";
import Leaderboard from "./Pages/Leaderboard";
function App() {
return (
<div>
<Route path = "/welcome">
<Welcome />
</Route>
<Route path = "/game">
<Game />
</Route>
<Route path = "/leaderboard">
<Leaderboard />
</Route>
</div>
);
}
export default App;
File index.js
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from "./App";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
I get the following error:
Error: A Route is only ever to be used as the child of
element, never rendered directly. Please wrap your Route in a Routes.
Where have I gone wrong?
Yes, in react-router-dom version 6 it is a bit different. Please look as the sample below.
React Router tutorial
import { render } from "react-dom";
import {
BrowserRouter,
Routes,
Route
} from "react-router-dom";
import App from "./App";
import Expenses from "./routes/expenses";
import Invoices from "./routes/invoices";
const rootElement = document.getElementById("root");
render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="expenses" element={<Expenses />} />
<Route path="invoices" element={<Invoices />} />
</Routes>
</BrowserRouter>,
rootElement
);
There was a fairly decent change between versions 5 and 6 of react-router-dom. It appears that the Udemy course/tutorial is using version 5 where all you needed was a Router to provide a routing context and Route components just needed to be rendered within this context. In version 6, however, the Route components now need to be rendered within a Routes component (which is an upgrade from the v5 Switch component).
Introducing Routes
One of the most exciting changes in v6 is the powerful new <Routes>
element. This is a pretty significant upgrade from v5's <Switch>
element with some important new features including relative routing
and linking, automatic route ranking, and nested routes and layouts.
The error message is pretty clear, wrap your Route components in a Routes component. The routes also don't take children (other than other Route components in the case of nested routes), they render the components as JSX on the new element prop.
function App() {
return (
<div>
<Routes>
<Route path="/welcome" element={<Welcome />} />
<Route path="/game" element={<Game />} />
<Route path="/leaderboard" element={<Leaderboard />} />
</Routes>
</div>
);
}
The problem is your react-router-dom version.
Probably it's 5.1 or higher.
You can try (in terminal):
npm install react-router-dom#5.3.0
And then your code will be OK. Or you better rebuild your code according to new react-router-dom.
import React from 'react'
import {BrowserRouter, Route, Routes } from 'react-router-dom'
import './App.css';
import Navbar from './components/Navbar';
import { Home } from './components/screens/Home';
import { Login } from './components/screens/Login';
import { Profile } from './components/screens/Profile';
import { Signup } from './components/screens/Signup';
function App() {
return (
<BrowserRouter>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
<Route path="/profile" element={<Profile />} />\
</Routes>
</BrowserRouter>
);
}
export default App;
In the latest version of React, 'Switch' is replaced with 'Routes' and 'component' is replaced with 'element'
Enter image description here
Try to wrap your routes by Routes:
import { Route, Routes } from "react-router-dom";
import Welcome from "./Pages/Welcome";
import Game from "./Pages/Game";
import Leaderboard from "./Pages/Leaderboard";
function App() {
return (
<div>
<Routes>
<Route path = "/welcome">
<Welcome />
</Route>
<Route path = "/game">
<Game />
</Route>
<Route path = "/leaderboard">
<Leaderboard />
</Route>
</Routes>
</div>
);
}
export default App;
I think there are many problems that can lead to that issue.
react-router-dom version 6 no longer supports the use of components directly. Use an element to specify the component you route.
Route has to be a child of Routes
Use the simple snippet.
import logo from './logo.svg';
import './App.css';
import Navbar from './components/Navbar';
import {BrowserRouter, Routes, Route, Link} from 'react-router-dom';
import Homescreen from './screens/Homescreen';
function App() {
return (
<div className="App">
<Navbar/>
<BrowserRouter>
<Routes>
<Route path='/home' element={<Homescreen/>} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
The problem right here is that you are using React v5. Since React v6, several changes were included in Router.
So now, to make it work, and as your error message says, you need to wrap your Route element inside a Routes element (Routes now is the equivalent, but an improved version of Switch element). Also, you need to add an "element" prop that accepts JSX instead of wrapping inside the Route element.
So, to make it work, you need to import all these elements like this:
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
That being said, your code should look like this:
<Router>
<Routes>
<Route path="/" element={<Welcome/>}>
</Route>
<Route path="/" element={<Game />}>
</Route>
<Route path="/" element={<Leaderboard />}>
</Route>
</Routes>
</Router>
It's probably because you are using version 6 or higher of react-router-dom.
Try:npm i react-router-dom#5.2.0
And it should work.
In the newer version of react-router-dom, we need to nest the Route inside the Routes. Also, component and exact have been removed in newer version.
I was facing same issue and solve it.
Though I am using
react-router-dom#6
So I had to modify app.js and index.js like below
in index.js
import { BrowserRouter } from "react-router-dom";
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
and app.js
import { Routes, Route } from "react-router-dom";
function App() {
return (
<>
<Header />
<main className="py-3">
<Container>
<Routes>
<Route path="/" element={<HomeScreen />} exact/>
</Routes>
</Container>
</main>
<Footer />
</>
);
}
export default App;
according to official documentation
Now, React uses React Router version 6
For React Router version 6, your index.js file is correct:
File index.js:
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from "./App";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
But your App.js file is not correct for React Router version 6, so this is the correct one below:
I changed three parts as shown below:
File App.js
// 1. "Routes" is imported
import { Routes, Route } from "react-router-dom";
import Welcome from "./Pages/Welcome";
import Game from "./Pages/Game";
import Leaderboard from "./Pages/Leaderboard";
function App() {
return (
<div> // 2. With "<Routes></Routes>", surround "3 <Route /> tags"
<Routes> // 3. Put an element with a component to each "<Route />"
<Route path = "/welcome" element={<Welcome />} />
<Route path = "/game" element={<Game />} />
<Route path = "/leaderboard" element={<Leaderboard />} />
</Routes>
</div>
);
}
export default App;
Use the element option to set your component instead of nesting it into the route tags. Then wrap all the routes with <Routes></Routes>.
Do not forget to add Routes to your imports
import { Route, Routes } from "react-router-dom";
import Welcome from "./Pages/Welcome";
import Game from "./Pages/Game";
import Leaderboard from "./Pages/Leaderboard";
function App() {
return (
<div>
<Routes>
<Route path = "/welcome" element={<Welcome />}/>
<Route path = "/game" element={<Game />}/>
<Route path = "/leaderboard" element={<Leaderboard />}/>
</Routes>
</div>
);
}
export default App;
Use:
<div>
<Header />
</div>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/profile" element={<Profile />} />
<Route path="/about" element={<About />} />
</Routes>
I know I'm late but there is another way to do nested routes straight from javascript.
first import
import { useRoutes } from "react-router-dom";
secondly, declare your routes. Here is a quick example
function App() {
return useRoutes([
{
path: "/",
element: <Example/>
},
{
path: "/contact",
element: <Example/>
}]);
}
so now you can have unlimited nested components doing it this way.
in your index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root")); //where App must rendered in real DOM?in root
root.render(<App />); //jsx code is a special syntax that browser not undrestand it!
and in your App.js
import { BrowserRouter, Routes, Route } from "react-router-dom";
import AllMeetupsPage from "./pages/AllMeetups";
import NewMeetupPage from "./pages/NewMeetup";
import FavoritesPage from "./pages/Favorites";
function App() {
return (
<div>
<BrowserRouter>
<Routes>
<Route path="/" element={<AllMeetupsPage />} />
<Route path="/new-meetup" element={<NewMeetupPage />} />
<Route path="/favorites" element={<FavoritesPage />} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
There is another way to fix the version issues:
App.js File:
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Welcome from "./Pages/Welcome";
import Game from "./Pages/Game";
import Leaderboard from "./Pages/Leaderboard";
function App() {
return (<div>
<BrowserRouter>
<Routes>
<Route path = "/Welcome" element={< Welcome/>}/>
<Route path = "/Game" element={< Game/>}/>
<Route path = "/LeaderBoard" element={< LeaderBoard/>}/>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
Index.js file:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

react-router-dom v6 renders a Route when it is supposed to not render it

I want to render private routes for logged in users. For some reason react-router-dom (v6) renders private routes even if PrivateRoute returns null. Also, I couldn't see any console.logs from inside PrivateRoute. Any ideas?
EDIT
It renders Dashboard when you go to localhost/dashboard and Settings when you go to localhost/settings, even though both components are passed to PrivateRoute, which returns null.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from 'react-router-dom';
import App from './App';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById('root'));
App.js
import {Route, Routes} from 'react-router-dom';
import {Home} from './components/Home';
import {Pricing} from './components/Pricing';
import {Dashboard} from './components/Dashboard';
import {Settings} from './components/Settings';
import {Login} from './components/Login';
import {Header} from './components/Header';
import {PrivateRoute} from './components/PrivateRoute';
const App = () => {
return (
<div>
<Header />
<Routes>
<Route path='/' element={<Home/>} />
<Route path='/pricing' element={<Pricing />} />
<PrivateRoute path='/dashboard' element={<Dashboard />} />
<PrivateRoute path='/settings' element={<Settings />} />
<Route path='/login' element={<Login />} />
</Routes>
</div>
);
};
export default App;
PrivateRoute.js
export const PrivateRoute = ({path, element}) => {
console.log('PrivateRoute'); **// couldn't see this in the console**
return null;
};
Unfortunately, according to the documentation, the new way to do this looks like this:
<Route
path="/protected"
element={
<RequireAuth>
<ProtectedPage />
</RequireAuth>
}
/>
https://reactrouter.com/docs/en/v6/examples/auth
Full code exemple:
https://stackblitz.com/github/remix-run/react-router/tree/main/examples/auth?file=src/App.tsx

Installed React-Router - The URL changes, but not the view

I am using React-Router for the first time. I am trying to get the buttons on the homepage to go to its respective URL, but When I click on a button, the URL changes, but not the view. I don't get any errors on the console, either. I was wondering if somebody can point out what is happening. I wrapped each button with a link, and assigned the path it needs to go to when clicked. I was wondering if anyone can point out what I am doing wrong.
Homepage.js
import React from 'react';
import {Link} from "react-router-dom"
class HomePage extends React.Component {
render(){
return (
<div>
<h1>Welcome</h1>
<p>Please select a category </p>
<Link to="/ProgrammingJokes">
<button>Programming Jokes</button>
</Link>
<Link to="/DadJokes">
<button>Dad Jokes</button>
</Link>
<Link to="/SportsJokes">
<button>Sports Jokes</button>
</Link>
</div>
)
}
}
export default HomePage;
App.js
import React from 'react';
import HomePage from './components/HomePage'
import DadJokesApi from './components/DadJokesApi'
import SportsJokesApi from './components/SportsJokesApi'
import ProgrammingJokesApi from './components/ProgrammingJokesApi';
import { Route, Switch} from "react-router-dom";
function App() {
return (
<main>
<Switch>
<Route path="/" component={HomePage} />
<Route path="/DadJokes" component={DadJokesApi} />
<Route path="/SportsJokes" component={SportsJokesApi} />
<Route path="/ProgrammingJokes" component={ProgrammingJokesApi} />
</Switch>
</main>
);
}
export default App;
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>,
document.getElementById('root')
);
Try placing your root route at the end of the list.
Since:
A <Switch> looks through its children <Route>s and renders the first
one that matches the current URL.
From https://reacttraining.com/react-router/web/guides/quick-start
<Switch>
<Route path="/DadJokes" component={DadJokesApi} />
<Route path="/SportsJokes" component={SportsJokesApi} />
<Route path="/ProgrammingJokes" component={ProgrammingJokesApi} />
<Route path="/" component={HomePage} />
</Switch>
Your Switch is matching with the first route every time. You need to use
<Route exact path = '/' component = {Component}/>
You can use the exact property on your routes.
When true, will only match if the path matches the location.pathname exactly.
You can read more here https://reacttraining.com/react-router/web/api/Route/exact-bool
The result must be something like this:
<Route path="/DadJokes" exact component={DadJokesApi} />

React Router v5 nested routes not found

I'm having problems trying to make a simple setup to run. I have used "react-router-dom" because it claims to be the most documented router around.
Unfortunately, the documentation samples are using functions instead of classes and I think a running sample will not explain how routes have changed from previous versions... you need a good sight!. Btw, there are a lot of breaking changes between versions.
I want the following component structure:
Home
Login
Register
Recipes
Ingredients
Have the following components:
index.js (works fine)
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route } from 'react-router-dom';
import App from './App';
ReactDOM.render((
<BrowserRouter>
<Route component={App}/>
</BrowserRouter>
), document.getElementById('root'));
App.js (fine)
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import Home from './Home'
import Recipes from './recipes/Recipes'
import Ingredients from './ingredients/Ingredients'
class App extends React.Component {
render() {
return (
<div id="App">
<Switch>
<Route exact path='/home' component={Home} />
<Route path='/recipes' component={Recipes} />
<Route path='/ingredients' component={Ingredients} />
<Route render={() => <h1>Not found!</h1>} />
</Switch>
</div>
);
}
}
export default YanuqApp;
Ingredients and Recipes components working fine, so I'll skip from here
Home.js - The problem starts here. Home itself loads correctly, but once Login or Register links are clicked, it shows "Not found!" (fallback route in App.js)
import React from 'react';
import { Switch, Route, Link } from 'react-router-dom';
import Register from './account/register'
import Login from './account/login'
class Home extends React.Component {
render() {
return (
<div>
<div>
This is the home page...<br/>
<Link to='/home/login'>Login</Link><br />
<Link to='/home/register'>Register</Link><br />
</div>
<Switch>
<Route path='/home/login' component={Login} />
<Route path='/home/register' component={Register} />
</Switch>
</div>
);
}
}
export default Home;
Login and register are very similar:
import React from 'react';
class Login extends React.Component {
render() {
alert("login");
return (
<div>Login goes here...</div>
);
}
}
export default Login;
And cannot figure why Login and Register are not found. I have tried also defining routes as:
<Link to={`${match.path}/register`}>Register</Link>
...
<Route path={`${match.path}/register`} component={Register} />
(don't see the gain on using match, as it renders as the expected "/home/register"), but the problem persists in identical way
I think it's because of the exact flag on the Route for home. It does not match the /home exact so it goes to the default not found page.
try to add this in App.js
<Switch>
<Route exact path='/' component={Home} />
<Route path='/recipes' component={Recipes} />
<Route path='/ingredients' component={Ingredients} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<Route render={() => <h1>Not found!</h1>} />
</Switch>
to this is work
<Link to={`${match.path}/register`}>Register</Link>
...
<Route path={`${match.path}/register`} component={Register} />
you should provide match as the props because cont access directly to the match to used it you should provide a match as this following
const namepage=({match})=>{
<Link to={`${match.path}/register`}>Register</Link>
...
<Route path={`${match.path}/register`} component={Register} />
})

Categories

Resources