I am using react router v5. Clicking the links, changes url, but component is still the same [duplicate] - react-router

I am building a Netflix clone application, and I am using react-router-dom v5 to switch between different pages. However, when I click the Link tag in Navbar.jsx, the URL changes, but the corresponding component doesn't render. I have consulted numerous StackOverflow posts on this topic, however, I can't get it to work. Below is the code. Please help me, as I'm stuck on this for 3 days 😥.
What it should show, when navigating to /series from /:
What it is actually showing:
index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
const container = document.getElementById("root");
const root = createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
App.jsx
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import "./app.scss";
import Home from "./pages/home/Home";
import Watch from "./pages/watch/Watch";
const App = () => {
return (
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/movies">
<Home type="movies" />
</Route>
<Route path="/series">
<Home type="series" />
</Route>
<Route path="/watch">
<Watch />
</Route>
</Switch>
</Router>
);
};
export default App;
Home.jsx
import React from "react";
import Featured from "../../components/featured/Featured";
import Navbar from "../../components/navbar/Navbar";
import "./home.scss";
const Home = ({ type }) => {
return (
<div className="home">
<Navbar />
<Featured type={type} />
</div>
);
};
export default Home;
Navbar.jsx
import React, { useState } from "react";
import "./navbar.scss";
import { Link } from "react-router-dom";
const Navbar = () => {
const [isScrolled, setIsScrolled] = useState(false);
window.onscroll = () => {
setIsScrolled(window.scrollY === 0 ? false : true);
return () => window.onscroll == null;
};
return (
<div className={`navbar ${isScrolled ? "scrolled" : ""}`}>
<div className="container">
<img src="./netflix_logo.jpg"
alt="netflix logo"
/>
<Link to="/" className="link">
<span>Home</span>
</Link>
<Link to="/series" className="link">
<span>Series</span>
</Link>
<Link to="/movies" className="link">
<span>Movies</span>
</Link>
<Link to="" className="link">
<span>New and Popular</span>
</Link>
<Link to="" className="link">
<span>My List</span>
</Link>
</div>
</div>
);
};
export default Navbar;
Featured.jsx
import "./featured.scss";
import { IoMdPlay } from "react-icons/io";
import { FiInfo } from "react-icons/fi";
const Featured = ({ type }) => {
return (
<div className="featured">
{type && (
<div className="category">
<span style={{ color: "white" }}>
{type === "movies" ? "Movies" : "TV Series"}
</span>
<select name="genre" id="genre">
<option>Genre</option>
<option value="adventure">Adventure</option>
<option value="comedy">Comedy</option>
<option value="crime">Crime</option>
<option value="fantasy">Fantasy</option>
<option value="historical">Historical</option>
<option value="horror">Horror</option>
<option value="romance">Romance</option>
<option value="sci-fi">Sci-fi</option>
<option value="thriller">Thriller</option>
<option value="western">Western</option>
<option value="animation">Animation</option>
<option value="drama">Drama</option>
<option value="documentary">Documentary</option>
</select>
</div>
)}
<img
src="https://m.media-amazon.com/images/M/MV5BNzM4OTkzMjcxOF5BMl5BanBnXkFtZTgwMTkxMjI1MTI#._V1_.jpg"
alt="featured"
/>
<div className="info">
<img
src="https://occ-0-1432-1433.1.nflxso.net/dnm/api/v6/LmEnxtiAuzezXBjYXPuDgfZ4zZQ/AAAABUZdeG1DrMstq-YKHZ-dA-cx2uQN_YbCYx7RABDk0y7F8ZK6nzgCz4bp5qJVgMizPbVpIvXrd4xMBQAuNe0xmuW2WjoeGMDn1cFO.webp?r=df1"
alt=""
/>
<span className="desc">
When a beautiful stranger leads computer hacker Neo to a forbidding
underworld, he discovers the shocking truth - the life he knows is the
elaborate deception of an evil cyber-intelligence.
</span>
<div className="buttons">
<button className="play">
<IoMdPlay className="button-logo" />
<span>Play</span>
</button>
<button className="more">
<FiInfo className="button-logo" />
<span>More Info</span>
</button>
</div>
</div>
</div>
);
};
export default Featured;

There's a compatibility issue between pre-5.3.3 versions of react-router-dom#5 and react#18.
Github Issue #7870
PR #8831 merged to address issue - Fix was merged on May 18th, 2022, react-router-dom v5.3.3.
Solutions
Bugfix was merged into v5.3.3. Update to react-router-dom#5.3.3 or higher.
From the project's root directory run:
npm uninstall -S react-router-dom
npm install -S react-router-dom#5.3.3 (or #latest)
Revert back to React 17 (or React 17 syntax) and fix up the index.js file.
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(
<StrictMode>
<App />
</StrictMode>,
document.getElementById("root")
);
Make the React.StrictMode component a child/descendent of the router component. Comment.
Replace:
<React.StrictMode>
...
<BrowserRouter>
...
</BrowserRouter>
</React.StrictMode>
with:
<BrowserRouter>
<React.StrictMode>
...
</React.StrictMode>
</BrowserRouter>
Upgrade to react-router-dom#6 and fix up the routes.
const App = () => {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/movies" element={<Home type="movies" />} />
<Route path="/series" element={<Home type="series" />} />
<Route path="/watch" element={<Watch />} />
</Routes>
</Router>
);
}

First Solution and Best Solution:
If you use are using React Router 5.3.x, check whether it is 5.3.3 in your package.json file.
If it is not 5.3.3 uninstall the last version then install the bug-free version which has been resolved by John and updated in version 5.3.3.
npm uninstall -S react-router-dom
npm install -S react-router-dom#5.3.3
Second Solution:
React has launched its StrictMode in its latest update.
you can see it in an index.js file
index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
So here your React Router is in the child component. And we have to make it a parent component.
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>
);
Third Solution:
Remove the Strict mode from the index.js file
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);

Related

React Router v5 not rendering route when clicking link [duplicate]

I am building a Netflix clone application, and I am using react-router-dom v5 to switch between different pages. However, when I click the Link tag in Navbar.jsx, the URL changes, but the corresponding component doesn't render. I have consulted numerous StackOverflow posts on this topic, however, I can't get it to work. Below is the code. Please help me, as I'm stuck on this for 3 days 😥.
What it should show, when navigating to /series from /:
What it is actually showing:
index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
const container = document.getElementById("root");
const root = createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
App.jsx
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import "./app.scss";
import Home from "./pages/home/Home";
import Watch from "./pages/watch/Watch";
const App = () => {
return (
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/movies">
<Home type="movies" />
</Route>
<Route path="/series">
<Home type="series" />
</Route>
<Route path="/watch">
<Watch />
</Route>
</Switch>
</Router>
);
};
export default App;
Home.jsx
import React from "react";
import Featured from "../../components/featured/Featured";
import Navbar from "../../components/navbar/Navbar";
import "./home.scss";
const Home = ({ type }) => {
return (
<div className="home">
<Navbar />
<Featured type={type} />
</div>
);
};
export default Home;
Navbar.jsx
import React, { useState } from "react";
import "./navbar.scss";
import { Link } from "react-router-dom";
const Navbar = () => {
const [isScrolled, setIsScrolled] = useState(false);
window.onscroll = () => {
setIsScrolled(window.scrollY === 0 ? false : true);
return () => window.onscroll == null;
};
return (
<div className={`navbar ${isScrolled ? "scrolled" : ""}`}>
<div className="container">
<img src="./netflix_logo.jpg"
alt="netflix logo"
/>
<Link to="/" className="link">
<span>Home</span>
</Link>
<Link to="/series" className="link">
<span>Series</span>
</Link>
<Link to="/movies" className="link">
<span>Movies</span>
</Link>
<Link to="" className="link">
<span>New and Popular</span>
</Link>
<Link to="" className="link">
<span>My List</span>
</Link>
</div>
</div>
);
};
export default Navbar;
Featured.jsx
import "./featured.scss";
import { IoMdPlay } from "react-icons/io";
import { FiInfo } from "react-icons/fi";
const Featured = ({ type }) => {
return (
<div className="featured">
{type && (
<div className="category">
<span style={{ color: "white" }}>
{type === "movies" ? "Movies" : "TV Series"}
</span>
<select name="genre" id="genre">
<option>Genre</option>
<option value="adventure">Adventure</option>
<option value="comedy">Comedy</option>
<option value="crime">Crime</option>
<option value="fantasy">Fantasy</option>
<option value="historical">Historical</option>
<option value="horror">Horror</option>
<option value="romance">Romance</option>
<option value="sci-fi">Sci-fi</option>
<option value="thriller">Thriller</option>
<option value="western">Western</option>
<option value="animation">Animation</option>
<option value="drama">Drama</option>
<option value="documentary">Documentary</option>
</select>
</div>
)}
<img
src="https://m.media-amazon.com/images/M/MV5BNzM4OTkzMjcxOF5BMl5BanBnXkFtZTgwMTkxMjI1MTI#._V1_.jpg"
alt="featured"
/>
<div className="info">
<img
src="https://occ-0-1432-1433.1.nflxso.net/dnm/api/v6/LmEnxtiAuzezXBjYXPuDgfZ4zZQ/AAAABUZdeG1DrMstq-YKHZ-dA-cx2uQN_YbCYx7RABDk0y7F8ZK6nzgCz4bp5qJVgMizPbVpIvXrd4xMBQAuNe0xmuW2WjoeGMDn1cFO.webp?r=df1"
alt=""
/>
<span className="desc">
When a beautiful stranger leads computer hacker Neo to a forbidding
underworld, he discovers the shocking truth - the life he knows is the
elaborate deception of an evil cyber-intelligence.
</span>
<div className="buttons">
<button className="play">
<IoMdPlay className="button-logo" />
<span>Play</span>
</button>
<button className="more">
<FiInfo className="button-logo" />
<span>More Info</span>
</button>
</div>
</div>
</div>
);
};
export default Featured;
There's a compatibility issue between pre-5.3.3 versions of react-router-dom#5 and react#18.
Github Issue #7870
PR #8831 merged to address issue - Fix was merged on May 18th, 2022, react-router-dom v5.3.3.
Solutions
Bugfix was merged into v5.3.3. Update to react-router-dom#5.3.3 or higher.
From the project's root directory run:
npm uninstall -S react-router-dom
npm install -S react-router-dom#5.3.3 (or #latest)
Revert back to React 17 (or React 17 syntax) and fix up the index.js file.
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
ReactDOM.render(
<StrictMode>
<App />
</StrictMode>,
document.getElementById("root")
);
Make the React.StrictMode component a child/descendent of the router component. Comment.
Replace:
<React.StrictMode>
...
<BrowserRouter>
...
</BrowserRouter>
</React.StrictMode>
with:
<BrowserRouter>
<React.StrictMode>
...
</React.StrictMode>
</BrowserRouter>
Upgrade to react-router-dom#6 and fix up the routes.
const App = () => {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/movies" element={<Home type="movies" />} />
<Route path="/series" element={<Home type="series" />} />
<Route path="/watch" element={<Watch />} />
</Routes>
</Router>
);
}
First Solution and Best Solution:
If you use are using React Router 5.3.x, check whether it is 5.3.3 in your package.json file.
If it is not 5.3.3 uninstall the last version then install the bug-free version which has been resolved by John and updated in version 5.3.3.
npm uninstall -S react-router-dom
npm install -S react-router-dom#5.3.3
Second Solution:
React has launched its StrictMode in its latest update.
you can see it in an index.js file
index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
So here your React Router is in the child component. And we have to make it a parent component.
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>
);
Third Solution:
Remove the Strict mode from the index.js file
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);

Using react-router with reconcilers such as react-three-fiber

I'm try to use react-router with react-three-fiber. The issue is the <Switch> components lose their context when added inside a react-three-fiber <Canvas> element. To fix this I can wrap the switch inside a <Router> inside the Canvas. And the routes work as expected when manually typing the url. However, the ` elements now seem to reference another Router and don't work when clicked.
Is there a way to make the elements inside and outside the <Canvas> reference the same router?
https://codesandbox.io/s/reach-router-starter-v1-9qcjc
const App = ({ router }) => {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
<Canvas>
<Plane color="black" position={[-5, 0, 0]} />
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</Router>
</Canvas>
</div>
</Router>
);
};
const Home = () => <Plane color="red" position={[0, 0, 0]} />;
const About = () => <Plane color="green" position={[0, 0, 0]} />;
const Dashboard = () => <Plane color="blue" position={[0, 0, 0]} />;
You can use npm i wouter instead of react-router-dom https://www.npmjs.com/package/wouter
Wrap everything as you normally would using react-router-dom but use wouter instead. Note that top level Router component is fully optional.
App.js :
import Nav from './Nav'
import { Router, Switch, Route } from 'wouter';
make App.js a class component and structure like so:
<Nav />
<Router/>
<Switch />
<Route exact path="/somelink" component={Somecomponent}/>
<Switch />
<Router/>
export default App;
Nav.js component:
import { Link } from 'wouter'
const Nav = () => {
return (
<nav className="navigation">
<ul>
<li>
<Link to="/somecomponent">...</Link>
</li>
</ul>
</nav>
)
}
export default Nav;

Routing not working in reactjs application

I have created a reactjs app having three pages (components), App, Login and Register, where I need to navigate from page to page by entering the url in the browser but the navigation is not working for me. Entering any url just shows me the 'App' page.
following is the code that I have written in main.js file of the app and the url that I am using to navigate looks something like this http://localhost:8080/#/login or http://localhost:8080/#/reg
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, NavLink, Redirect, Switch, hashHistory} from 'react-router-dom'
import App from './../jsx/App.jsx';
import Login from './../jsx/Login.jsx';
import Register from './../jsx/Register.jsx';
ReactDOM.render((
<Router history={hashHistory}>
<div>
<Route path="/" component={App}/>
<Route path="/login" component={Login}/>
<Route path="/reg" component={Register}/>
</div>
</Router>
), document.getElementById('app'))
You need to configure the route to match the root path exactly. Try this...
<Route exact path="/" component={App}/>
Remove / from your path in Route path in
<Route path="/login" component={Login}/>
<Route path="/reg" component={Register}/>
try this it's working for me
entry class
import React from 'react';
import ReactDOM from 'react-dom';
import Layout from './Component/Layout.jsx';
import { Router, Route, IndexRoute, hashHistory } from "react-router";
import Archives from './Component/Archives.jsx';
import Settings from './Component/Settings.jsx';
import Featured from './Component/Featured.jsx';
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={Layout}>
//<IndexRoute component={Featured}></IndexRoute>
<Route path="archives" name="archives" component={Archives}></Route>
<Route path="settings" component={Settings}></Route>
<Route path="featured" component={Featured}></Route>
</Route>
</Router>,
document.getElementById('app'));
Layout class
{
render{
return(
<div>
{this.props.children}
<ul>
<li><Link to="archives">archives</Link></li>
<li><Link to="settings">settings</Link></li>
<li><Link to="featured">featured</Link></li>
</ul>
</div>
);
}
}
If you are using react router 4, then that looks fine. However, you can try using a as shown below:
<BrowserRouter>
<Switch>
<Route path="/" component={Home} />
</Switch>
</BrowserRouter>
This is in latest versions of react. The Home component is as below:
render() {
return (
<div>
<p>Header Section</p>
<Header/>
<p>Home component</p>
<Link to="/search">search</Link>
<Route path="/search" component={Search}/>
</div>
);
}
So most probably what you need to do is to just add a switch. Other solutions may be possible too. Hope this helps :)
Use BrowserRouter and Switch from 'react-router-dom'
if you use BrowserRouter no need to pass history as props as it handles itself.
Try this.
<Router>
<Switch>
<Route exact path="/" component={App}/>
<Route exact path="/login" component={Login}/>
<Route exact path="/reg" component={Register}/>
</Switch>
</Router>

React JS component with nested navigation

I've been having some trouble with the following. I've tried for a few hours to find some help through searching, but have come up empty handed. It could be that I don't know the name of what I'm trying to do, but I figured I'd ask here.
I've been learning React for about a month. Currently I'm trying to create a component which has it's own navigation bar and displays it's content based on which link in the component's navigation bar is clicked.
I have a Navigation bar for the entire website, using React Router, and I've tried nesting the component's route in the Route for the page I want it displayed, but when I click on a link within said component, instead of simply having the content displayed within that component, I'm navigated to a new page (in this case: localhost3000/#/project1). That new page displays the entire component, with the correct content. However, I want to avoid navigating to a new page.
Here's a pic of what I want to do.
Here's some of the code I've got so far. (I've omitted the imports and anything else unnecessary.
My index.js
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={OtherPage}></IndexRoute>
<Route path="Project_Page" component={ProjectPage} />
<Route component={ProjectsComponent}>
<Route path="project1" component={Project1} />
<Route path="project2" coponent={Project2} />
<Route path="project3" coponent={Project3} />
</Route>
<Route path="Another_Page" component={AnotherPage}></Route>
</Route>
</Router>
,
document.getElementById('root')
);
My ProjectPage.js
export default class ProjectPage extends Component{
render(){
return(
<div>
<ProjectsComponent />
</div>
);
}
}
My ProjectsComponent.js
export default class ProjectsComponent extends Component{
render(){
return(
<div>
<ProjectsNav /> // this is the navbar for my projects component
<div>
{this.props.children}
</div>
</div>
);
}
}
My ProjectsNav.js
export default class ProjectsNav extends Component{
render(){
return(
<div>
<Link to="Project1" className="btn btn-primary">Project 1</Link>
<Link to="Project2" className="btn btn-primary">Project 2</Link>
<Link to="Project3" className="btn btn-primary">Project 3</Link>
</div>
);
}
}
Finally
My Project1.js project2 && project3 are pretty much the same thing.
export default class Project1 extends Component{
render(){
return(
<div className="project">
Hello from Project 1
</div>
);
}
}
I'm sorry if this is something that's already been covered. If it has, please feel free to point me in the right direction. That's really all I need.
Thank you so much for your help.
ProjectsComponent component is not required, Try these components:
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={OtherPage}></IndexRoute>
<Route path="Project_Page" component={ProjectPage}>
//<Route component={ProjectsComponent}>
<IndexRoute path="Project_Page/Project1" component={Project1} />
<Route path="Project_Page/Project2" coponent={Project2} />
<Route path="Project_Page/Project3" coponent={Project3} />
</Route>
<Route path="Another_Page" component={AnotherPage}></Route>
</Route>
</Router>
,
document.getElementById('root')
);
export default class ProjectPage extends Component{
render(){
return(
<div>
<ProjectsNav />
<div>
{this.props.children}
</div>
</div>
);
}
}
export default class ProjectsNav extends Component{
render(){
return(
<div>
<Link to="Project_Page/Project1" className="btn btn-primary">Project 1</Link>
<Link to="Project_Page/Project2" className="btn btn-primary">Project 2</Link>
<Link to="Project_Page/Project3" className="btn btn-primary">Project 3</Link>
</div>
);
}
}
Let me know if u face any issue or want any help.

Basename not working properly

I'm attempting to use a basename with react-router as documented on the react-router docs. This is due to base href being deprecated.
Here is what I have now:
import { Route, Router, useRouterHistory } from 'react-router';
import { createHistory } from 'history';
import { render } from 'react-dom';
var history = useRouterHistory(createHistory)({
basename: '/subdirectory'
});
render(
<Router history={history}>
<Route path='/' component={App}>
<Route path='next' component={Next} />
</Route>
</Router>,
document.getElementById('root')
);
When I go to http://the-url.com/subdirectory the page loads as expected (rendering the App component). However, when going to http://the-url.com/subdirectory/next, I get a 404 error. My nginx config is:
location /subdirectory {
alias /path/to/index.html;
index index.html;
try_files $uri $uri/ /path/to/index.html;
}
Here is how I managed to get it to work
Set Router basename to your subdirectory like this
<Router basename="/subdirectory">
If you used create-react-app and are building using npm run build you need to set homepage in package.json for the paths to be correct in the production build
homepage: "{http://www.the-url.com/subdirectory}"
For the nginx config, let's assume your index.html is under /path/to/subdirectory/index.html. Then the following should work
location /subdirectory {
root /path/to;
try_files $uri $uri/ /subdirectory/index.html;
}
I solved it by using:
import { Router, useRouterHistory } from 'react-router'
import createBrowserHistory from 'history/lib/createBrowserHistory'
const history = useRouterHistory(createBrowserHistory)({
basename: '/',
})
<Router history={history}>
I think the issue was different versions of the history package. react-router#2.2.4 uses history#2.1.2, while history is already at 4.5.1.
So make sure you install the correct version of the history package.
Using BrowserRouter
helpers/history.js
import { createBrowserHistory } from "history";
export default createBrowserHistory();
index.js
import {BrowserRouter as Router} from "react-router-dom";
import history from "helpers/history";
.....
<Router history={history} basename={'/app'}>
...
</Router>
Using Router
helpers/history.js
import { createBrowserHistory } from "history";
export default createBrowserHistory({ basename: '/app' });
index.js
import {Router} from "react-router-dom";
import history from "helpers/history";
....
<Router history={history}>
...
</Router>
This is too sad that react documentation does not specify anything regarding basename in react router v6. however, I tried something and it worked. please find below solution. cheers!
<HashRouter>
<Routes>
<Route path='/app'> {/* put url base here and nest children routes */}
<Route path='path1' element={ <Somecomponent1 /> } />
<Route path='path2' element={ <Somecomponent2 /> } />
</Route>
<Route path="/*" element={<Navigate to="/app/path1" />} /> {/* navigate to default route if no url matched */}
</Routes>
</HashRouter>
<HashRouter>
<Routes>
<Route path='/app'> {/* put url base here and nest children routes */}
<Route path='path1' element={ <Somecomponent1 /> } />
<Route path='path2' element={ <Somecomponent2 /> } />
</Route>
<Route path="/*" element={<Navigate to="/app/path1" />} /> {/* navigate to default route if no url matched */}
</Routes>
</HashRouter>
I was struggling this issue from 2 days approx. This article was very helpful for me.