React Routing still showing root component even after using exact - reactjs

I am still a newbie to React. So here I am rendering the root component with two routes: Home and About located in functional components: home.js and about.js respectively. However, even after using exact attribute and , the root component keeps on rendering above. I still cannot figure out how to not render the root component when I am redirecting to any of the mentioned routes?
Heres the live demo: https://codesandbox.io/s/vmz6zwq0k7

The Route component is acting like a "placeholder" for the component you want to render when the URL matches. everything above it (parents and siblings) wont get affected.
Given this code example:
render() {
return (
<BrowserRouter>
<div className="App">
<Link to="/home"> Home </Link>{" "}
|
<Link to="/about"> About Us </Link>{" "}
<div>
<Route exact path="/home" component={Home} />
<Route exact path="/about" component={About} />
</div>
</div>
</BrowserRouter>
);
}
This line of code:
<Route exact path="/home" component={Home} />
Is only a "placeholder" for the Home component. It won't render anything only when the path is matching "/home".
When the path will match, the Route component will render the passed component, The Home component in this case.
It will not affect the entire app tree, and for a good reason!
If the entire app would get re-rendered and replaced with the Home component you would loose the navigation links.

I had the same problem looking at the react-routing getting started portion here. https://reactrouter.com/web/guides/quick-start
I placed my Router/BrowserRouter in my App component. Instead place the router in your index.js file like so
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
Then your app component can look like so and the root route wont be matched if about or users is matched.
import React from "react";
import {
Switch,
Route,
Link
} from "react-router-dom";
export default function App() {
return (
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</nav>
{/* A <Switch> looks through its children <Route>s and
renders the first one that matches the current URL. */}
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Users() {
return <h2>Users</h2>;
}

Related

Why do my Link To links not work in React-Router?

Trying to create an about page for a website im working on, I found this solution on Stack but it does not work for me. I was using an outdated tutorial for my original code, this is my current code:
About.js:
import React from "react";
import { Link, Route, useMatch } from "react-router-dom";
import SinglePage from "./SinglePage";
const About = () => {
//const match = useMatch('/');
return (
<div className="about__content">
<ul className="about__list">
<li>
<Link to={'about-app'}>About App</Link>
</li>
<li>
<Link to={'about-author'}>About Author</Link>
</li>
</ul>
<Route path={':slug'}>
<SinglePage />
</Route>
</div>
);
};
export default About;
Index.js where I am rendering the component:
import React from "react";
import ReactDOM from "react-dom";
import TodoContainer from "./functionBased/components/TodoContainer"; // Component file
import "./functionBased/App.css"; // Style sheet
import { HashRouter as Router, Routes, Route } from "react-router-dom"; // Router file
import About from "./functionBased/pages/About";
import NotMatch from "./functionBased/pages/NotMatch";
ReactDOM.render(
<React.StrictMode>
<Router>
<Routes>
<Route exact path="/" element={<TodoContainer />} />
<Route path="/about/*" element={<About />} />
<Route path="*" element={<NotMatch />} />
</Routes>
</Router>
</React.StrictMode>,
document.getElementById("root")
);
Issues
The About component is directly rendering a Route component. The Route component can only be rendered by a Routes component or another Route component as a nested route.
The react-router-dom#6 Route components render their content on the element prop.
Solution
Import the Routes component and wrap the descendent Route component rendered by `About.
Render SinglePage on the route's element prop.
Example:
import React from "react";
import { Link, Routes, Route } from "react-router-dom";
import SinglePage from "./SinglePage";
const About = () => {
return (
<div className="about__content">
<ul className="about__list">
<li>
<Link to="about-app">About App</Link>
</li>
<li>
<Link to="about-author">About Author</Link>
</li>
</ul>
<Routes>
<Route path=":slug" element={<SinglePage />} />
</Routes>
</div>
);
};
export default About;
Alternative
You could alternatively move the SinglePage route out to the main router as a nested route (instead of where it is as a descendent route).
Example:
import React from "react";
import { Link, Outlet } from "react-router-dom";
import SinglePage from "./SinglePage";
const About = () => {
return (
<div className="about__content">
<ul className="about__list">
<li>
<Link to="about-app">About App</Link>
</li>
<li>
<Link to="about-author">About Author</Link>
</li>
</ul>
<Outlet />
</div>
);
};
export default About;
...
<Router>
<Routes>
<Route path="/" element={<TodoContainer />} />
<Route path="/about" element={<About />}>
<Route path=":slug" element={<SinglePage />} />
</Route>
<Route path="*" element={<NotMatch />} />
</Routes>
</Router>
You are defining the routes with /about/* and accessing them with about-something which does not exist at all, add \about\author in to for Link.

React.js: npm start shows a different default route

I'm new to react and I have a weird problem that every time I do npm start, I get on the same
page! how do I change it? (tried with few projects! the same page!)
routing:
import { Redirect, Route, Switch } from "react-router-dom";
import { Page404 } from "./Page404";
import { Login } from "./Login";
import { Logout } from "./Logout";
import { Register } from "./Register";
export const Routing = () => {
return (
<div>
<Switch>
<Route path="/login" component={Login} />
<Route path="/logout" component={Logout} />
<Route path="/register" component={Register} />
<Redirect exact from="/" to="/login" />
<Route component={Page404} />
</Switch>
</div>
);
};
and the default route that I always get is:
http://localhost:3000/login-auth
EVERY time after npm start.
btw that started to happen when I installed firebase.
in this project I'm not even using firebase and it keeps happening
Thanks!
first edit
I've noticed that I didn't mention important parts:
first: I don't have a home component yet (wanted to practice log in pages)
second: the app component: which contain the router {i needed the router that way because the header using it as well}
import "./App.css";
import { Routing } from "./Components/Routing";
import "notyf/notyf.min.css";
import { BrowserRouter } from "react-router-dom";
import { MenuBar } from "./Components/MenuBar/MenuBar.jsx";
function App() {
return (
<div className="App">
<BrowserRouter>
<header>
<MenuBar />
</header>
<body>
<Routing />
</body>
</BrowserRouter>
</div>
);
}
I've tried to uninstall firebase (although I'm not using it in this project)
and it did not work as well
** I SOLVED IT! **
I had a "homepage" setting in my package.json that lead me there for some reason
I'm confused, first of all why didnt you rap up your <Switch></Switch> in <Router/> tag?
Mostly the router file structure is like this
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</nav>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Users() {
return <h2>Users</h2>;
}
I think instead of http://localhost:3000/login-auth, you want to see http://localhost:3000. If that's the problem:
It goes to login page because you have <Redirect exact from="/" to="/login" />
Even if you delete this line, you will still face problems, because I cannot see your home component. Where is it?
And also you need to wrap your routing with <Router> and <Switch> tags as ASWIN CHANDRON noted.
Also, I kindly advise you to update your knowledge to new React syntax. And to use exact keyword. So, instead of <Route path="/login" component={Login} /> use <Route exact path="/login"><Login /></Route>
And also instead of import { Login } from "./Login"; you can type import Login from "./Login";
I've solved it, the problem was in the package.json, i had "homepage" option and it just throw me there after npm start

Router Issue in React Js (component for showing)

I am new to ReactJs and I want to navigate to another component on button click. I just want to perform a simple routing. This is the code that I tried. But I am not able to route it.
in App.js
import React from 'react';
import DepartmentShow from './Components/Departments/DepartmentShow';
import {BrowserRouter, Link, Route, Switch} from 'react-router-dom'
<BrowserRouter>
<Link to = '/departments'>Departments</Link>
<Switch>
<Route path='/customers' component= {CustomerList} exact={true} />
<Route path='/customers/new' component= {AddCustomer} />
<Route path='/customers/edit/:id' component= {EditCustomer} />
<Route path='/customers/:id' component= {CustomerShow} />
<Route Path='/departments' component={ListDepartment} exact={true}/>
<Route exact Path='/departments/:id' component={DepartmentShow} />
</Switch>
</BrowserRouter>
ListDepartment.js
<ul>
{
props.department.map((dept)=>{
return <li key={dept._id}><Link to={`/departments/${dept._id}`}>{dept.name}</Link>
<button onClick={()=>{handleRemove(dept._id)}}>remove</button>
<Link to={`/departments/${dept._id}`}><button>Show</button></Link>
</li>
})
}
</ul>
Note: cuustomer component i can route but not department.. :(
DepartmentShow.js
import React from 'react'
function DepartmentShow (props){
return(
<div>
<h1>Show Details</h1>
</div>
)
}
export default DepartmentShow
When i click on show button my show component should show.
when i click on show i get url like http://localhost:3000/departments/5e922d889b38110016837a77
but its is not routing to show component.

<Link> in React doesn't forward to a new page

Consider the code :
import React from 'react';
import { Link, BrowserRouter } from 'react-router-dom';
import { ReactComponent as Logo } from '../../assets/crown.svg';
import './header.styles.scss';
const Header = () => (
<BrowserRouter>
<div className='header'>
<Link className='logo-container' to='/'>
<Logo className='logo' />
</Link>
<div className='options'>
<Link className='option' to='/shop'>
SHOP
</Link>
<Link className='option' to='/contact'>
CONTACT
</Link>
</div>
</div>
</BrowserRouter>
);
export default Header;
This is a header that I use in my App.
Look like this :
When I click on the crown the URL (in the browser) changes , but the page doesn't change , it stays on the same page.
Same thing happens with the other Links , CONTACT & SHOP.
What's wrong with the <Link> tag ? Why doesn't it forward to the to that's written on the Link tag ?
Did you setup the routes? This would be in AppRouter.js for example:
<BrowserRouter>
<div>
<Header />
<Switch>
<Route path='/' component={Home} exact={true} />
<Route path='/shop' component={Shop} exact={true }/>
<Route path='/contact' component={Contact} exact={true} />
<Route component={ErrorPage} />
</Switch>
</div>
</BrowserRouter>
If you want navigate your user try use NavLink
or add withRouter to component and push them to the other pages
-- NavLink solution :
import { NavLink, BrowserRouter } from 'react-router-dom';
and then in your JSX use this instead
<NavLink className='logo-container' to='/'>
<Logo className='logo' />
</NavLink>
-- push solution:
import { withRouter , BrowserRouter } from 'react-router-dom';
export your component like this
export default withRouter(Header);
then you can use any tags you want and listen at events on them
<p className='logo-container' onClick = {() => props.history.push('/')}>
<Logo className='logo' />
</p>
in order to navigate to different components you have to define routers. So react-router-dom will know what to display.
The other thing is u cannot put BrowserRouter inside the Header component. Component BrowserRouter wraps the history object in the browser and passes it to down to component tree. BrowserRouter is a wrapper. Header should be placed inside the BrowserRouter but not here. just create your Header Component without BrowserRouter.
here is how you should properly implement routing in react.js
in src/omponents folder create your components for routes.
src/component/shop.js:
import React from "react";
const Shop = () => <div>my shop component</div>; //define your component
export default Shop;
create all other components like so including Header but without BrowserRouter. then in src folder create a new directory name routers. inside of it create AppRouter.js
src/routers/AppRouter.js
import { BrowserRouter, Route, Switch } from "react-router-dom";
import React from "react";
import Shop from "../components/Shop";
//import all other routes from components directory.
import Header from "../components/Header"
const AppRouter = () => (
<BrowserRouter>
<div>
<Header />
<Switch>
<Route path="/" component={YourHomeComponent} exact={true} />
<Route path="/contact" component={Contact} />
<Route path="/shop" component={Shop} />
<Route component={NotFound} />
</Switch>
</div>
</BrowserRouter>
);
export default AppRouter;
// When react-router sees “Switch” it is going to move through your route definitions in order and it’s going to stop when it finds a match.
finally in app.js
import React from "react";
import ReactDOM from "react-dom";
import AppRouter from "./routers/AppRouter";
ReactDOM.render(<AppRouter />, document.getElementById("app"));

React router displaying component when it shouldn't

Based on my understanding, once you have implemented React Router, your website should not display any components unless the Route path matches the URL. However, my code is not behaving that way. I have things implemented, but the Invoices component is still wanting to render, even though the URL is '/'. How do I fix this problem?
UPDATED to prevent components from rendering and to show more code for LeftMenu
I'm still confused on whether or not I even need to use React Router for my situation.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './pages/App';
import { BrowserRouter as Router } from 'react-router-dom';
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById('root'),
);
App.js
return (
<>
<GlobalStyle />
<TopMenu
setDisplay={setDisplay}
display={display}
openNav={openNav}
closeNav={closeNav}
/>
<Wrapper>
<LeftMenu changeSection={changeSection} setSection={setSection} />
<MainStyle>
<BreadCrumbs
changeSection={changeSection}
number={number}
month={month}
breadCrumbs={breadCrumbs}
setSection={setSection}
/>
<Portal>
{section === 'home' && <Home />}
{section === 'invoice' && (
<Invoice>
<Invoices
invoices={invoices}
updateNumber={updateNumber}
updateMonth={updateMonth}
number={number}
month={month}
download={download}
/>
</Invoice>
)}
{section === 'act' && <ACT />}
{section === 'external' && <External />}
</Portal>
</MainStyle>
</Wrapper>
</>
);
LeftMenu.js
const LeftMenu = ({ changeSection }) => {
return (
<NavWindow>
<ul>
<li>
<Link to='/Employer Invoices'>Employer Invoices</Link>
</li>
<li>
<Link to='/ACT'>Enroll Employee</Link>
</li>
<li>
<Link to='/ACT'>Terminate Employee</Link>
</li>
<li>
<Link to='/ACT'>Employee Changes</Link>
</li>
</ul>
<Switch>
<Route exact path='/' component={Home} />
<Route path='/Employer Invoices' component={Invoices} />
<Route path='/Employer Invoices/:invoiceId' component={Invoices} />
<Route path='/Enroll Employee' component={ACT} />
<Route path='/Terminate Employee' component={ACT} />
<Route path='/Employee Changes' component={ACT} />
</Switch>
</NavWindow>
);
};
First, there is no link between your LeftMenu component and you App component here. Your leftMenu will never be rendered, and your App will always render all it contains(Home, Invoice, ACT, External...).
Second, the following assertion:
once you have implemented React Router, your website should not display any components unless the Route path matches the URL
is false.
In your context, if you change your index.js code from that:
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById('root'),
);
to that:
ReactDOM.render(
<Router>
<LeftMenu />
</Router>,
document.getElementById('root'),
);
I guess that it will get close to what you want. It will always render your NavWindow. Links inside will always be rendered, and above the ul tag will be rendered the component whose route match current path.
Here is a fiddle with you code and some modification to make it work, I let you discover the differences. Don't hesitate if you want more explanations.
https://jsfiddle.net/6atxpr15/
You need to wrap App in a Route component (https://reacttraining.com/react-router/web/api/Route) :
import { BrowserRouter as Router, Route } from 'react-router-dom'
ReactDOM.render(
<Router>
<Route path='/' component={App} />
</Router>
document.getElementById('root'),
);

Resources