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

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.

Related

react router not working and no erros in console or compilation error is shown [ react router dom v5]

Until now the router was working perfectly fine but suddenly it isn't working. I'm totally confused and I haven't done any kind of upgrades.
The router doesn't render the components itself. I wonder if even the correct route gets rendered based on path.
Only the first route is working fine, the other two don't seem to work.
AssetPage.js
import React from "react";
import { Route } from "react-router-dom";
import AssetNavBar from "./AssetNavBar";
import "./assets.css";
function AssetPage() {
return (
<div className="top-div">
<header>
<AssetNavBar />
</header>
<main className="main-flex">
<Route path="/assets/add" exact><h1>in main</h1></Route>
<Route path="/assets/storage">
<h1>in storage</h1>
</Route>
<Route path="/assets/view">
<h1>in view</h1>
</Route>
</main>
</div>
);
}
export default AssetPage;
AssetNavBar.js
import React from "react";
import {Link} from 'react-router-dom';
function AssetNavBar() {
return (
<div>
<nav>
<ul className="ul-side-by-side">
<li>
<Link to="/assets/add">add assets</Link>
</li>
<li>
<Link to="/assets/view">view assets</Link>
</li>
<li>
<Link to="/assets/storage">storage</Link>
</li>
</ul>
</nav>
</div>
);
}
export default AssetNavBar;
index.js - [starting point]
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import {BrowserRouter} from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
App.js
import "./App.css";
import { Route } from "react-router-dom";
import SingleItem from "./components/inventory/SingleItem"
import HomeNavBar from "./components/HomeNavBar";
import InventoryPage from "./components/inventory/InventoryPage";
import ProductPage from "./components/products/ProductPage";
import PurchasePage from "./components/purchase/PurchasePage";
import SupplierPage from "./components/supplier/SupplierPage";
import AssetPage from "./components/assetFolder/AssetPage";
function App() {
return (
<div className='horizontal-div-boxes'>
<header>
<HomeNavBar/>
</header>
<main className="main-flex">
<Route path="/dashboard">
<SingleItem />
</Route>
<Route path='/inventory'>
<InventoryPage/>
</Route>
<Route path='/purchase'>
<PurchasePage/>
</Route>
<Route path='/products/add'>
<ProductPage/>
</Route>
<Route path='/suppliers/add'>
<SupplierPage/>
</Route>
<Route path='/assets/add'>
<AssetPage/>
</Route>
</main>
</div>
);
}
export default App;
version
└─┬ react-router-dom#5.3.0
└── react-router#5.2.1
Issue
The AssetPage component is rendered on a "/assets/add" path and there are no other "/assets*" paths, so the other two links don't link to any routes that render content.
<Route path='/assets/add'>
<AssetPage />
</Route>
In other words, when you link to "/assets/view" or "/assets/storage" the path no longer matches "/assets/add" and the AssetPage component is unmounted.
Solution
I am sure that you want this root route to be just "/assets" to allow further matching any "/assets*" paths.
<Route path='/assets'>
<AssetPage />
</Route>

NavLink does not add activeClassName (react-router-dom v5.2.0)

I have a small problem with Nav Link.
It doesn't apply active Class Name, although it otherwise works (goes to the desired path, renders the required component)
react-router-dom version 5.2.0
my index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './components/App';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
and my Navigation.js:
import { NavLink } from 'react-router-dom';
function Navigation() {
return (
<nav className="navigation">
<ul className="navigation__list">
<li>
<NavLink to="/" activeClassName="navigation__item_active" className="navigation__item">
Home
</NavLink>
</li>
<li>
<NavLink to="/frontend" className="navigation__item" activeClassName="navigation__item_active">
frontend
</NavLink>
</li>
<li>
<NavLink to="/about" className="navigation__item" activeClassName="navigation__item_active">
about
</NavLink>
</li>
</ul>
</nav>
);
}
export default Navigation;
UPD:
Router works, trouble in NaVLink.
I need to add activeClassName to nav item, but it doesnt.
my App.js:
import React from 'react';
import Header from './Header';
import Footer from './Footer';
import Main from './Main';
function App() {
return (
<div className="App">
<Header/>
<Main/>
<Footer/>
</div>
);
}
export default App;
and Main.js:
import React from 'react';
import { Route } from 'react-router-dom';
import HelloPage from './Hello-page';
import About from './About';
import Frontend from './Frontend';
import Navigation from './Navigation';
function Main() {
return (
<main className="main">
<Route exact path="/">
<HelloPage/>
</Route>
<Route path="/about">
<About/>
</Route>
<Route path="/frontend">
<Frontend/>
</Route>
<Navigation/>
</main>
);
}
export default Main;
it fixed by 1 command... (10+ hours of my live)
npm i path-to-regexp#1.7.0 -S
It should already work tho~
Btw, even if you applied those activeClassName. You still need to tweak your code in App.js to something like this:-
need to add Redirect only for the home or / route. If not, the activeClassName will be applied always for home or / route
App.js:-
export default function App() {
return (
<Router>
<Nav />
<Switch>
{/* Add this Redirect */}
<Redirect exact from="/" to="/home" />
<Route path="/home" component={() => "Home page"} />
<Route path="/demo" component={() => "Demo page"} />
<Route path="/demo2" component={() => "Demo2 page"} />
</Switch>
</Router>
);
}
You can see this working sandbox
Try to delete the Redirect and see how it changes
As mentioned here in my case solution was replace in webpack
resolve: {
modules: [
path.resolve('./src'),
- path.resolve('./node_modules'),
+ 'node_modules',
],
},

Link not re-directing to a page in React

I am trying to make a Navbar but the isn't re-directing to the given page. If I click any of the links in the Navbar, it would change the path in the url bar but won't re-direct to that page. I am not sure if I am missing anything. When I replace it with the tags, it works perfectly.
Navbar.js
import React from "react";
import { BrowserRouter as Router, Link, Switch } from "react-router-dom";
const Navbar = () => {
return (
<Router>
<Switch>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/articles">Articles</Link>
</li>
<li>
<Link to="/articles-all">All articles</Link>
</li>
</ul>
</nav>
</Switch>
</Router>
);
};
export default Navbar;
App.js
import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import './App.css'
//pages
import Home from "./Pages/Home";
import About from "./Pages/About";
import Articles from "./Pages/Articles";
import ArticlesList from "./Pages/ArticlesList";
//components
import Navbar from './components/Navbar';
const App = () => {
return (
<div>
<Navbar/>
<Navigation />
</div>
);
};
export default App;
const Navigation = () => {
return (
<Router>
<div id="page-body">
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/articles" component={Articles} />
<Route path="/articles-all" component={ArticlesList} />
</div>
</Router>
);
};
Since you define the Router within Navigation and another one in Navbar your Links are not able to communicate to the Router Component in Navigation as they just communicate to their nearest parent Router component
You must you use a single Router instance to be able to perform seemless navigation within your App. Also a Switch component is not needed with Links but with Route
const App = () => {
return (
<Router>
<Router component={Navbar}/> // rendered as default route so that they receive router props
<Router component={Navigation} />
</Router>
);
};
export default App;
const Navigation = () => {
return (
<div id="page-body">
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/articles" component={Articles} />
<Route path="/articles-all" component={ArticlesList} />
</div>
);
};
const Navbar = () => {
return (
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/articles">Articles</Link>
</li>
<li>
<Link to="/articles-all">All articles</Link>
</li>
</ul>
</nav>
);
};
export default Navbar;
Here's a working codesandbox URL https://codesandbox.io/s/frosty-black-3i8hp?file=/src/App.js
You were wrapping links with browserRouter and Switch. These APIs are intended to wrap Routes only.
So, It wasn't able to communicate well with your react app.

<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 Routing still showing root component even after using exact

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>;
}

Resources