HashRouter URL is updated on click but component not (blocking updates) - reactjs

I've created an app via create-react-app. I want to use the HashRouter functionality for my app (React Router v4), but it is not working as expected.
Actually I don't know why. I.e. when I click on the contact link, then the URL changes to the route /contacts, but the related component is not being showed. It still shows the previous loaded component. The links are placed in the Navigation component. Here is one example of a Link.
<Link key={"navigation" + bu.name + "Key"}
to="/products"
className="nav-link dropdown-item imageLink animated"
onClick={(e) => this.handleClickBU(e, bu.bu)}>{bu.name}
</Link>
This is my code of App.js:
import React, { Component } from "react";
import {
BrowserRouter as Router,
HashRouter,
Route,
Link,
Switch
} from "react-router-dom";
<HashRouter>
<div>
<Background />
<div id="wrap">
<div id="main" className="container clear-top marginBottom50px main">
<div id="content">
<Navigation
key="navBar"
languagesToShow={this.state.languagesToShow}
currentLanguage={this.state.currentLanguage}
onLanguageChange={this.handleLanguageChange.bind(this)}
onBUChange={this.handleBUChange.bind(this)}
onIndustryChange={this.handleIndustryChange.bind(this)}
onCountryChange={this.handleCountryChange.bind(this)}
/>
<Route
key={"mainPageRoute"}
path={"/"}
exact={true}
render={(routeProps) => (
<MainPage
{...routeProps}
currentLanguage={this.state.currentLanguage}
country={this.state.countryObject}
contacts={this.state.contacts}
onCountryChange={this.handleCountryChange.bind(this)}
/>
)}
/>
<Route
key={"contactRoute"}
path={"/contact"}
exact={true}
render={(routeProps) => (
<ContactList
{...routeProps}
showCountrySelection={true}
currentLanguage={this.state.currentLanguage}
country={this.state.countryObject}
contacts={this.state.contacts}
onCountryChange={this.handleCountryChange.bind(this)}
key={"contactList"}
/>
)}
/>
<Route
key={"productsRoute"}
path={"/products"}
exact={true}
render={(routeProps) => (
<Products
{...routeProps}
ref={this.props.innerRef}
key="products"
isLoading={this.state.isLoading}
country={this.state.countryObject}
currentLanguage={this.state.currentLanguage}
currentBU={this.state.currentBU}
showMainProductGroups={this.state.showMainProductGroups}
showMainProductGroupDetails={
this.state.showMainProductGroupDetails
}
showProductGroupDetails={this.state.showProductGroupDetails}
mainProductGroups={this.state.mainProductGroups}
onShowMainProductGroupDetailsChange={this.handleShowMainProductGroupDetailsChange.bind(
this
)}
onShowProductGroupDetailsChange={this.handleShowProductGroupDetailsChange.bind(
this
)}
onBUChange={this.handleBUChange.bind(this)}
onCountryChange={this.handleCountryChange.bind(this)}
/>
)}
/>
</div>
</div>
</div>
</div>
</HashRouter>;
Can anyone tell me, why the url is updated, but the component not?
UPDATE
I already searched a lot and I found this link on the react training site.
I tried different things, but no one did not solve my problem.
But when I change HashRouter to Router it works fine!!! Why!?!
Can it be an issue / bug of HashRouter?

Related

React Router 6.3.0 render component twice [duplicate]

This question already has answers here:
Why useEffect running twice and how to handle it well in React?
(2 answers)
Closed 6 months ago.
I'm new to React and try to create my first SPA with React Router.
I try to do it with a functional components.
For now it's very basic but even now I faced a problem which I cannot resolve - component renders twice every time I use proper routing.
Problem appeared when I started to use useEffect hook to call simple console.log() on component initialisation. I noticed every time I choose Autosearch from a Navbar React Router render proper component but I can see two logs Called! in a browser console. I've tried recompose structure of my HTML but it didn't work.
index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>
);
App.js
function App() {
return (
<div className="container-background h-auto">
<div className="container-lg p-2">
<Header/>
<Navbar/>
<section className="content p-4">{<ContentDisplay/>}</section>
<Footer/>
</div>
</div>
);
}
Navbar.js
const Navbar = () => {
return (
<React.Fragment>
<nav className="navbar nav-custom">
<span className="navbar-collapse">
<div className="nav">
<NavLink className="nav-item nav-link text-white" to={"/reversed"}>Reversed</NavLink>
<NavLink className="nav-item nav-link text-white" to={"/autosearch"}>AutoSearch</NavLink>
<NavLink className="nav-item nav-link text-white" to={"/about"}>About</NavLink>
</div>
</span>
</nav>
</React.Fragment>
);
}
ContentDisplay.js
const ContentDisplay = () => {
return (
<>
<Routes>
<Route path="/" exact element={<Home/>} />
<Route path="/reversed" exact element={<Reversed />} />
<Route path="/autosearch" exact element={<Autosearch />} />
<Route path="/about" exact element={<About />} />
<Route path="*" element={<ErrorPage />} />
</Routes>
</>
)
}
Autosearch.js
const Autosearch = () => {
useEffect(() => {
console.log("Called!")
}, []);
return(
<>
Autosearch
</>
)
}
The whole view hierarchy in your app is child of StrictMode (index.js)
In dev mode a double rendering is the intended behavior.
This does not affect production mode.
https://reactjs.org/docs/strict-mode.html

how to use top loader bar in react js App

I am new in react js I want to implement npm i react-top-loading-bar in my react app. I am using react class function component. i want to implement that see the picture
if anyone clicks on the Navigation link then it will show a loading bar at the top
if anyone know that how to implement this please let me know, it is very helpful for me
navbar.js
import React, { useEffect } from 'react'
import { Link, useLocation } from 'react-router-dom'
import './Navbar.css'
import LoginRounded from '#mui/icons-material/LoginRounded'
import Button from '#mui/material/Button';
const Navbar = () => {
//Navbar active color change
let location = useLocation();
useEffect(() => {
}, [location]);
return (
<div>
<nav className="navbar navbar-expand-lg navbar-dark" style={{ backgroundColor: "#063970" }}>
<div className="container-fluid">
<Link className="navbar-brand" to="/">Evalue Content</Link>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav me-auto mb-2 mb-lg-0">
<li className="nav-item">
<Link className={`nav-link ${location.pathname === "/" ? "active" : ""}`} to="/">Home</Link>
</li>
<li className="nav-item"><Link className={`nav-link ${location.pathname === "/service" ? "active" : ""}`} to="/service">Service</Link></li>
<li className="nav-item"><Link className={`nav-link ${location.pathname === "/contact" ? "active" : ""}`} to="/contact">contact us</Link></li>
</ul>
<Button component={Link} to="/Login" variant="contained" size="medium" startIcon={<LoginRounded />} sx={{ marginLeft: 'auto' }} >Login</Button>
</div>
</div>
</nav>
</div>
)
}
export default Navbar
App.js
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './components/Home';
import Navbar from './components/Navbar';
import Contact from './components/Contact';
import Service from './components/Service'
import Login from './components/Login';
// Redirect to their dashboar
import Admin from './components/dashboard/Admin';
import Employee from './components/dashboard/Employee';
import Publisher from './components/dashboard/Publisher';
//Toast error message show
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import Reset from './components/Reset';
import Newpassword from './components/Newpassword';
//admin Routes
import Project from './components/dashboard/AdminPages/Project'
import User from './components/dashboard/AdminPages/User';
function App() {
return (
<div>
<Router>
<Navbar />
<Routes>
<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 />} />
{/* Redirect to their dashboard */}
<Route exact path="/admin" element={<Admin />} />
<Route exact path="/employee" element={<Employee />} />
<Route exact path="/publisher" element={<Publisher />} />
{/* admin pages */}
<Route exact path="/publisher" element={<Project />} />
<Route exact path="/user" element={<User />} />
</Routes>
</Router>
<ToastContainer
position="top-right"
autoClose={4000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
/>
</div>
);
}
export default App;
Loading bar is not useful thing in React, because React is one page website and all the data is shown in your website is already downloaded from the server. However, we all use this for inner peace, and it gives a good user experience.
To solve this problem, you need to follow a few steps.
Install this below given line in your terminal.
npm i react-top-loading-bar
Import Loading bar from react top.
import LoadingBar from 'react-top-loading-bar
Copy this line and paste it in your "app.js" file.
Now for loading bar we need color, progress, and onLoaderFinisher. Put this lines wherevery you want the LoadingBar, mostly people prefer below the Navbar.
<LoadingBar
color='#f11946'
progress={progress}
/>
Also, You have to add setProgress() method, which helps to change the progress.
state={
prgress:0
}
setProgress = (progress) =>{
this.setState({this.state.progress:progress})
}
Now, you have to pass this method to your component. Here, you are using multiple component such as, Home, Service, Contact, and many more. So, pass this method with every component.
i.g.
<Route exact path="/" element={<Home setProgress={this.setProgress} />} />
This is consider as a props, so now where you want to show your progress bar just use as a props.
like,
this.props.setProgress(0);
//then put your code here in middle, where your data is fetch/ shown, where your process takes a few seconds, and then
this.props.setProgress(100);

React routing link from nested component

I want to add routing to my app but the "Link" I made in a child component doesn't work onClick, but only when I refresh the page. I guess the problem is the way too much nesting but I have no idea how can I solve it.
One mention: I imported BrowserRouter as Router everywhere.
This is the file structure
This is the code spippets that related to my problem:
App component:
function App() {
return (
<Router >
<div className="App">
<Switch>
<Route exact path="/" component={NewFetch} />
<Route path="/cardID/:id" component={Details} /> //The route that doesn't work
</Switch>
</div>
</Router>
NewFetch (Main) component:
<Router> //Tried with <React.Fragment>
...
<Route path={["/cards/:name", "/cards/:filter"]}>
<Filter isLoaded={isLoaded} handleScroll={handleScroll} toScrollTop={toScrollTop} value={value}
scrollPosition={scrollPosition} jumpToTop={jumpToTop} testFilter={testFilter} />
</Route>
</Router>
Card (child 2) component from :
const Card = (props) => {
return (
<div className={props.img ? "card" : "hide"}>
<Link to={`/cardID/id=${props.id}`} > //Link that doesn't connect
<img src={props.img} alt={props.name} />
</Link>
</div>
)
};
So basically I can't connect the "Link" from a hardly nested component.
function App() {
return (
<Router >
<div className="App">
<Switch>
<Route exact path="/" component={NewFetch} />
<Route path="/cardID/:id" component={Details} /> //The route that doesn't work
</Switch>
</div>
</Router
const Card = (props) => {
return (
<div className={props.img ? "card" : "hide"}>
<Link to={`/cardID/id=${props.id}`} > //Link that doesn't connect
<img src={props.img} alt={props.name} />
</Link>
</div>
)
};
Above is your code which might look right but the is a slight bug here:
The bug is in the wrong way you are linking to path="/cardID/:id
What you are to do is in your Card child2 is:
const Card = (props) => {
return (
<div className={props.img ? "card" : "hide"}>
<Link to={`/cardID/${props.id}`} > //Removed **id=....**
<img src={props.img} alt={props.name} />
</Link>
</div>
)
};
This is what you have to understand that when you make a route like so path="/route/:id" the :id is just a placeholder waiting for you to place anything so id is commonly used so your code makes sense and mainly basically you want to route based on id but one could have written :cat for example but that is just a placeholder

React Nested Routing by `:id`

I am trying to create a blog style app with an "articles" page that has a list of posts which will render by postId. I have gotten the urls to generate and even my small <Post /> component to render, but when a post page renders the Articles content doesn't go away and the post content just renders below it. How do I fix this?
I have
App.js:
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/articles">
<Articles />
</Route>
</Switch>
Articles.js:
import React from 'react';
import {
Link,
useRouteMatch,
Switch,
Route,
} from 'react-router-dom';
import Post from '../Components/Post';
import Banner from './Banner';
const Articles = () => {
let match = useRouteMatch();
return (
<div className='Articles'>
<Banner title='Articles'/>
<h3>Please select a topic.</h3>
<ul>
<li>
<Link to={`${match.url}/geojsons`}>Geojsons</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
<Switch>
<Route path={`${match.url}/:postId`}>
<Post />
</Route>
</Switch>
</div>
)
}
export default Articles;
Post.js:
function Post() {
let { postId } = useParams();
return <h3>POST - Requested topic ID: {postId}</h3>;
}
export default Post;
Screen shot of problem page:
This screenshot shows the page after you click on an article link. The Post content is what I have in the dashed red box and everything above it should only be a part of the Articles page.
I know it is only a couple files but to make it easier to mess with I put a simplified version of the repo on github. No styling or anything just an html version of the problem.
Since you want Article and Posts pages to be separate, you need to decouple your post route from Article route and render it in App.js instead of Articles.js
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/articles/:postId">
<Post />
</Route>
<Route exact path="/articles">
<Articles />
</Route>
</Switch>
and in Article.js
const Articles = () => {
let match = useRouteMatch();
return (
<div className='Articles'>
<Banner title='Articles'/>
<h3>Please select a topic.</h3>
<ul>
<li>
<Link to={`${match.url}/geojsons`}>Geojsons</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>
Props v. State
</Link>
</li>
</ul>
</div>
)
}

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