react-boostrap and react-router causing full page reload - reactjs

I am just trying to get React-Boostrap and React-Router up and running together. I used Create React App to create a simple shell.
This is my code, which does actual work nicely with React Router
import React, { Component } from "react";
import { RouteComponentProps, useHistory } from 'react-router';
import {
BrowserRouter as Router,
Switch,
Route,
useParams,
BrowserRouter
} from "react-router-dom";
import 'bootstrap/dist/css/bootstrap.min.css';
import {
Nav,
Navbar
} from "react-bootstrap";
function Navigation() {
return (
<BrowserRouter >
<div>
<Navbar bg="light" expand="lg">
<Navbar.Brand href="#home">React-Bootstrap</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto">
<Nav.Link href="/">Home</Nav.Link>
<Nav.Link href="/about">About</Nav.Link>
<Nav.Link href="/users/1">/users/1</Nav.Link>
<Nav.Link href="/users/2">/users/2</Nav.Link>
<Nav.Link href="/users2/1">/users2/1</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
{/* 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/:id" render={() => <Users />}/>
<Route path="/users2/:id" component={Users2} />
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</BrowserRouter >
);
}
class AppRouterBootstrap extends Component {
render() {
return (
<div id="App">
<Navigation />
</div>
);
}
}
export default AppRouterBootstrap;
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function Users() {
// We can use the `useParams` hook here to access
// the dynamic pieces of the URL.
let { id } = useParams();
let history = useHistory();
const handleClick = () => {
history.push("/home");
};
return (
<div>
<h3>ID: {id}</h3>
<button type="button" onClick={handleClick}>Go home</button>
</div>
);
}
class Users2 extends React.Component<RouteComponentProps, any> {
constructor(props: any) {
super(props);
}
render() {
return (
<div>
<h1>Hello {(this.props.match.params as any).id}!</h1 >
<button
type='button'
onClick={() => { this.props.history.push('/users/1') }} >
Go to users/1
</button>
</div>
);
}
}
Which looks like this when rendered. Which looks ok, and actually works (on a navigation, and parameters etc etc point of view just fine)
However what I am noticing is that whenever I click on one of the React-Boostrap nav links, there is a FULL network reload occurring, if I monitor the Network tab. If I do not use React-Boostrap nav, but instead use a simple react-router and some Link from react-router. this full reload is not occurring. It only seems to happen when using React-Boostrap nav links
Does anyone know if this is normal, should React-Boostrap nav when used with React-Router be doing this. I guess its possible since its not using the inbuilt React-Router Link classes, but rather its own Nav based items.
Anyone have any ideas on this one?

The Nav.Link will refresh the pages by default (same functionality as a href).
You need to change it to <Nav.Link as={Link} to="/"> instead of <Nav.Link href="/"> to fix the same where Link is from react-router-dom

Related

React Router need help routing

I'm a beginner front-end dev and I try to make an imaginary website. I'm learning to react router now. So when I try to click on the home/about or contact button, It doesn't open it. What am I doing wrong?
here's my code below :
my App code :
import React from 'react';
import './App.css';
import Navibar from './Components/Navibar';
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import Home from './Components/Home';
import About from './Components/About';
import Contact from './Components/Contact';
let App = () => {
return (
<Router>
<div className="App">
<Navibar/>
<div className="content">
<Switch>
<Route exact path="/">
<Home/>
</Route>
<Route exact path="/About">
<About/>
</Route>
<Route exact path="Contact">
<Contact/>
</Route>
</Switch>
</div>
</div>
</Router>
);
}
export default App;
and here's my navbar code :
import React from 'react';
import {Nav, Navbar, Container} from 'react-bootstrap';
import {Link} from 'react-router-dom';
let Navibar = () => {
return (
<>
<Navbar bg="dark" variant="dark">
<Container>
<Navbar.Brand href="#home">My Portfolio</Navbar.Brand>
<Nav className="me-auto">
<Link to="/">Home</Link>
<Link to="#about">About me</Link>
<Link to="#contact">Contact</Link>
</Nav>
</Container>
</Navbar>
</>
);
}
export default Navibar;
and here's my Home (the home/about and contact codes are the same) code :
import React from 'react';
let Home = () => {
return (
<>
<h2>Home</h2>
</>
);
}
export default Home;
I need help from a professional, because I'm getting stuck in this :)
The Navibar should link to the route paths you are rendering, not anchor tags (hashes) on the current page. The bootstrap Navbar.Brand component should also render a RRD Link component instead of a plain anchor tag with href attribute.
import React from 'react';
import { Nav, Navbar, Container} from 'react-bootstrap';
import { Link } from 'react-router-dom';
const Navibar = () => {
return (
<>
<Navbar bg="dark" variant="dark">
<Container>
<Navbar.Brand
as={Link} // <-- as a RRD Link component
to="/" // <-- to prop for Link component
>
My Portfolio
</Navbar.Brand>
<Nav className="me-auto">
<Link to="/">Home</Link> // <-- "/"
<Link to="/about">About me</Link> // <-- "/about"
<Link to="/contact">Contact</Link> // <-- "/contact"
</Nav>
</Container>
</Navbar>
</>
);
}
export default Navibar;
The App component should specify route paths that match what the navbar is linking to.
Also the routes App is rendering within the Switch component should be rendered in inverse order of route path specificity. In other words, render the more specific paths prior to the less specific paths. This is to attempt to match and render more specific paths and falling back to less specific paths. This also effectively eliminates the need to use the exact prop.
const App = () => {
return (
<Router>
<div className="App">
<Navibar />
<div className="content">
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</div>
</Router>
);
}

React Multipage NavBar reseting its state

Trying to set up a simple NavBar using react-bootstrap, I want to maintain in the state the active page, this is the component:
import React, { useState } from 'react';
import { Navbar, Nav } from 'react-bootstrap';
const Navigation = () => {
const [activeItem, setActivePage] = useState("initial");
return (
<>
<Navbar bg="primary" variant="dark">
<Navbar.Brand href="/page1">Navbar</Navbar.Brand>
<Nav activeKey={activeItem} onSelect={(e) => setActivePage(e)} className="mr-auto">
<Nav.Link eventKey="/page1" href="/page1">Page 1</Nav.Link>
<Nav.Link eventKey="/page2" href="/page2">Page 2</Nav.Link>
</Nav>
<p>current: {activeItem}</p>
</Navbar>
</>
)
}
export default Navigation;
And this is the main App.js:
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Navigation from './components/Navigation';
import Page1 from './routes/Page1';
import Page2 from './routes/Page2';
const App = () => (
<>
<Router>
<Navigation/>
<Switch>
<Route exact path="/page1" component={Page1}/>
<Route path="/page2" component={Page2}/>
</Switch>
</Router>
</>
);
export default App;
The issue I have is that the activeItem state variable gets reset every time a page loads. So activeItem is "initial" at the very beginning, when I click on a page it briefly changes to the proper eventKey but then immediately returns to "initial" when the page loads so the state is not preserved across page loads, but reset every time.
I'm new to react, already tried going to other posts and react-bootstrap documentation. If I change the href values to stay in the same page (e.g. by making href="#explora") everything works as intended.
What am I missing here to make react keep state in the NavBar across page routing?
You could check into the location object using the useLocation hook, the pathname property which contains the path for the current page and also with this approach you don't need to save the current page in any state. So, having said that your Navigation component it should look like this:
import React, { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { Navbar, Nav } from 'react-bootstrap';
const Navigation = () => {
const location = useLocation();
return (
<>
<Navbar bg="primary" variant="dark">
<Navbar.Brand href="/page1">Navbar</Navbar.Brand>
<Nav activeKey={location.pathname} className="mr-auto">
<Nav.Link href="/page1">Page 1</Nav.Link>
<Nav.Link href="/page2">Page 2</Nav.Link>
</Nav>
<p>current: {location.pathname}</p>
</Navbar>
</>
)
}
export default Navigation;
Have you tried to move the const [activeItem, setActivePage] = useState("initial"); into App.js file?
App.js :
import React, { useState } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Navigation from './components/Navigation';
import Page1 from './routes/Page1';
import Page2 from './routes/Page2';
const App = () => (
const [activeItem, setActiveItem] = useState('initial');
<>
<Router>
<Navigation
activeItem={activeItem}
setActiveItem={setActiveItem}
/>
<Switch>
<Route exact path="/page1" component={Page1}/>
<Route path="/page2" component={Page2}/>
</Switch>
</Router>
</>
);
export default App;
Navigation component:
import React, { useState } from 'react';
import { Navbar, Nav } from 'react-bootstrap';
const Navigation = ({ activeItem, setActivePage }) => {
return (
<>
<Navbar bg="primary" variant="dark">
<Navbar.Brand href="/page1">Navbar</Navbar.Brand>
<Nav activeKey={activeItem} onSelect={(e) => setActivePage(e)} className="mr-auto">
<Nav.Link eventKey="/page1" href="/page1">Page 1</Nav.Link>
<Nav.Link eventKey="/page2" href="/page2">Page 2</Nav.Link>
</Nav>
<p>current: {activeItem}</p>
</Navbar>
</>
)
}
export default Navigation;

"How to make a functional Navbar"

I'm fairly new to React and I'm trying to implement Navbar with react-bootstrap. I have the navigation bar set up but its not actually linking to any of my pages.
I've tried looking through the documentation but there's not much information there. I've looked at other posts but they all seem to be using older versions of react-bootstrap or not using it at all.
import React from "react";
import ReactDOM from "react-dom";
import "./components/stylesheets/index.css";
import * as serviceWorker from "./serviceWorker";
import "bootstrap/dist/css/bootstrap.min.css";
import App from "./App";
ReactDOM.render(<App />, document.getElementById("root"));
serviceWorker.unregister();
import React, { Component } from "react";
import "./components/stylesheets/App.css";
import NavBar from "./components/NavBar";
import Home from "./components/Home";
import About from "./components/About";
class App extends Component {
render() {
return <NavBar />;
}
}
export default App;
import React, { Component } from "react";
import { Navbar, Nav, Form, FormControl, Button } from "react-bootstrap";
import "./stylesheets/NavBar.css";
class NavBar extends Component {
state = {};
render() {
return (
<div id="bar">
<Navbar bg="light" variant="light">
<Navbar.Brand href="#home">CALC-U</Navbar.Brand>
<Nav className="ml-auto">
<Nav.Link href="#home">Home</Nav.Link>
<Nav.Link href="#about">About</Nav.Link>
<Nav.Link href="#updates">Updates</Nav.Link>
<Nav.Link href="#profile">Profile</Nav.Link>
</Nav>
</Navbar>
</div>
);
}
}
export default NavBar;
I want the app to open up to the Home page automatically, and then open up the other pages if the button is clicked on in the navBar.
Edit: I've created a working example, you can check the code: Codesandbox
Seems like you're not using react-router for handling the links.
First you need to wrap your component with a BrowserRouter like so:
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const app = (
<BrowserRouter>
<App />
</BrowserRouter>
);
ReactDOM.render(app, document.getElementById("root"));
And in NavBar.js, inside a <Switch /> component, you declare the routes:
import { Switch, Route, Link } from "react-router-dom";
//(...)
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
In your case, you case use Link component inside your Nav.Link:
<Nav className="ml-auto">
<Nav.Link as={Link} to="/">Home</Nav.Link>
<Nav.Link as={Link} to="/about">About</Nav.Link>
</Nav>
Same applies if you want to add more links to the NavBar.
Sample application using react-bootstrap for Navbar
App.js
function App() {
return (
<div>
<Router>
<NavBar />
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" exact component={About} />
<Route path="/updates" exact component={Updates} />
<Route path="/profile" exact component={Profile} />
</Switch>
</Router>
</div>
);
}
const Home = () => <h1>Home</h1>;
const About = () => <h1>About</h1>;
const Updates = () => <h1>Updates</h1>;
const Profile = () => <h1>Profile</h1>;
NavBar.js
class NavBar extends React.Component {
state = {};
render() {
return (
<div id="bar">
<Navbar bg="light" variant="light">
<Navbar.Brand href="/">CALC-U</Navbar.Brand>
<Nav className="ml-auto">
<Nav.Link href="/">Home</Nav.Link>
<Nav.Link href="/about">About</Nav.Link>
<Nav.Link href="/updates">Updates</Nav.Link>
<Nav.Link href="/profile">Profile</Nav.Link>
</Nav>
</Navbar>
</div>
);
}
}

How navbar and footer make fixed in react

i have a question about how keep navbar and footer components stable on route change, now when i change route, so when i click some page from navbar all page refreshing with navbar and footer.
i think somewhere i make a mistake.
here is my app component:
class App extends Component {
render() {
return (
<Router>
<div>
<Navbar/>
<main>
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/Whoweare' component={Whoweare}/>
<Route path='/Solution' component={Solution}/>
<Route path='/ContactUs' component={ContactUs}/>
</Switch>
</main>
<Footer/>
</div>
</Router>
);
}
}
export default App;
i place here navbar and footer outside of router Switch tag it's right, not?
It's navbar component:
import React from 'react';
import {Navbar, Nav, Button, Container, NavItem} from 'react-bootstrap';
const NavbarComp = () =>
<Navbar>
<Container>
<Navbar.Brand href="/">Logo</Navbar.Brand>
<Navbar.Toggle />
<Navbar.Collapse className="justify-content-end">
<Nav>
<NavItem>
<Nav.Link href='/Whoweare'>Who we are</Nav.Link>
</NavItem>
<NavItem>
<Nav.Link href='/Solution'>Solution</Nav.Link>
</NavItem>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
export default NavbarComp;
I'm not sure about the react bootstrap integration with react router dom.
Ideally you should be using Link from react-router-dom
so in your navbar import { Link } from 'react-router-dom'
and in change your NavItemto
<NavItem>
<Link to='/Solution'>Solution</Link>
</NavItem>
This will not refresh the page but instead update the component (view)
Hope this is helps you. :)
I think you should place the navbar and the footer outside of the router, that way those will always be there even when you change routes. I think this is what you are looking for?

Redirects to previous state once Nav Link clicked?

So I have a navbar that once the user clicks "Log out" it renders the navbar that the non-signed in user sees. So far I have that down, but my problem is that when I click one of the other clicks on my webpage, for example, the "About", the navbar render back to the "Log out" state. How do I go about fixing this? I think it is because in my App.js source code, the userId: 123(testing purposes), which is hardcoded and it always run this.
CustomNavbar.js
import React, { Component } from 'react'
import { Navbar, Nav, NavItem } from 'react-bootstrap';
class CustomNavbar extends Component {
render() {
if (this.props.userID === null) {
return (
<div>
<Navbar collapseOnSelect expand="md" bg="dark" variant="dark">
<Navbar.Brand href="/">
Ndnu's Notes
</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
</Navbar.Collapse>
</Navbar>
<Navbar className="footer text-center" fixed="bottom" expand="lg" bg="light">
<Nav.Link href="/contactus">Contact Us</Nav.Link>
<Nav.Link href="/privacyterms">Privacy & Terms</Nav.Link>
<Nav.Link href="/about">About</Nav.Link>
</Navbar>
</div>
)
} else {
return (
<div>
<Navbar collapseOnSelect expand="md" bg="dark" variant="dark">
<Navbar.Brand href="/">
Ndnu's Notes
</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
</Nav>
<Nav>
<Nav.Link eventKey={2} href="/myAccount"> <i class="fas fa-user"></i> My Account</Nav.Link>
<Nav.Link eventKey={1} href="/" onClick={this.props.logUserOut}> <i class="fas fa-sign-out-alt"></i> Log Out</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
{/* Footer */}
<Navbar fixed="bottom" bg="light">
<Nav.Link href="/contactus">Contact Us</Nav.Link>
<Nav.Link href="/privacyterms">Privacy & Terms</Nav.Link>
<Nav.Link href="/about">About</Nav.Link>
</Navbar>
</div>
)
}
}
}
export default CustomNavbar
App.js
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import LoginAndRegister from './LoginAndRegister'
import ContactUs from './Components/ContactUs.js';
import PrivacyTerms from './Components/PrivacyTerms.js';
import CustomNavbar from './Components/CustomNavbar.js';
import About from './Components/About.js';
import Table from './Components/Table.js';
class App extends React.Component {
constructor() {
super();
this.state = {
userID: 123
}
}
logUserOut = (e) => {
e.preventDefault()
this.setState({userID: null});
}
render() {
return (
<Router>
<div>
<CustomNavbar userID={this.state.userID} logUserOut={this.logUserOut} />
<Route exact strict path="/contactus" component={ContactUs} />
<Route exact strict path="/about" component={About} />
<Route exact strict path="/privacyterms" component={PrivacyTerms} />
{!this.state.userID && <LoginAndRegister userID={this.state.userID}/>}
<Table />
</div>
</Router>
)
}
}
export default App;
You better keep user loggedIn state in localstorage instead of checking in state. And check if user is logged in or not to render desired output.
You will have to keep user info on some central location where you can access it easily on some nested component instead of passing states as props down.
Other option could be context api to access user loggedIn state.
It seems on page reload state.userID value is not there after reload. From you code you are setting userID in constructor it will be called aging on mount phase of component life cycle.
Ping me incase of any query :)

Resources