React Multipage NavBar reseting its state - reactjs

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;

Related

React fullpageJS and react-router-dom

I am trying to use react fullpageJS and react router dom to create a carousel but it shows empty screen, Here's the code I am using:
APP.JS:
import { Route, Routes } from "react-router-dom";
import Navigation from "./routes/navigation/navigation.component";
import Home from "./components/home/home.component";
function App() {
const About = () => {
return (
<div>
<h1>This is about</h1>
</div>
);
};
return (
<div>
<Routes>
<Route path="/" element={<Navigation />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
</Route>
</Routes>
</div>
);
}
export default App;
Home.jsx:
import { useState, useEffect, React } from "react";
import ProjectPreview from "../project-preview/project-preview.component";
import ReactFullpage from "#fullpage/react-fullpage";
// import "fullpage.js/vendors/scrolloverflow";
import PROJECTS_DATA from "../../Projects";
const Home = () => {
const [projectsToPreview, setProjects] = useState([]);
useEffect(() => {
setProjects(PROJECTS_DATA);
}, []);
<ReactFullpage
render={() => {
return (
<ReactFullpage.Wrapper>
<ReactFullpage.Wrapper>
{projectsToPreview.map((project) => {
return (
<div className="section" key={project.id}>
<h1>Test</h1>
<ProjectPreview project={project} />
</div>
);
})}
</ReactFullpage.Wrapper>
</ReactFullpage.Wrapper>
);
}}
/>;
};
export default Home;
The rendered screen shows only the navbar component but the content in the slider appear neither on the screen nor in the javascript dom
index.js:
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
reportWebVitals();
Navigation.jsx
import { Link, Outlet } from "react-router-dom";
import { Nav, Navbar } from "react-bootstrap";
const Navigation = () => {
return (
<>
<Navbar expand="lg" variant="dark">
<Link className="navbar-brand" to="/">
LOGO
</Link>
<Nav className="ms-auto">
<Link className="nav-link" to="/about">
About
</Link>
</Nav>
</Navbar>
<Outlet />
</>
);
};
export default Navigation;
I suspect the issue is that the Navigation component isn't rendering an Outlet component for the nested routes to render their element into.
Navigation should render an Outlet.
Example:
import { Outlet } from 'react-router-dom';
const Navigation = () => {
...
return (
... nav and layout UI
<Outlet /> // <-- nested routes render content here
...
);
};

How can I hide component (Navbar) on landing page

How can I hide the navbar on my landing page('/')? I have tried using this.props.location and extending the navbar component and that dose not seem to work. I know this is simple but I can not for the life of me remember how to do it! I would rather not render the component just on the pages that I want to display it.
App.js
import React from 'react'
import Navbar from './Components/Navbar'
import {BrowserRouter as Router, Route} from 'react-router-dom';
import Home from './Components/Home'
import Welcome from './Components/Welcome'
import About from './Components/About'
import Contact from './Components/Contact'
function App() {
return (
<>
<useLocation>
{({ useLocation }) => {
if (useLocation.pathname !== "/") { return <Navbar/>; } }
}
</useLocation>
<Router>
<Route exact path="/" component={Welcome}/>
<Route path="/Home" component={Home}/>
<Route path="/About" component={About}/>
<Route path='/Whitepaper' component={WhitePaper}/>
</Router>
</>
);
}
export default App;
Navbar.js
import React from 'react';
import { Link } from 'react-router-dom';
import "../Component Stylesheets/Navbar.css"
const Navbar = (props) =>{
return(
<>
<nav className='navbar'>
<Link to="/Home">
<div className="logo"></div>
</Link>
<Link to="/Home">
<li className="nav-item nav-link">Home</li>
</Link>
<Link to="/About">
<li className="nav-item nav-link">About</li>
</Link>
<Link to="/Contact">
<li className="nav-item nav-link">Contact</li>
</Link>
</nav>
</>
)
}
export default Navbar
You can check what page it is and show it then. I think you mentioned trying this but you just might have been doing it the wrong way.
{props.location.pathname !== '/' ? <Navbar /> : null}
you need to import Location from your react-router.
And use the Location data before your <Router> block.
Below is a sample from other react router library which should work same way for react-router as well:
<Location>
{({ location }) => {
if (location.pathname !== "/") { return <NavBar/>; } }
}
</Location>
or you can make use of useLocation Hooks
like below to get the current path and exclude NavBar component
let location = useLocation();

React router not rendering components anymore except the default one

I took a break from my project for a day and today I come back to and suddenly i have an issue with my react router. I was messing around with adding more components but deleted them and now my Homepage, about, or gallery component dont render when I change the page with then navbar. The url still changes if i click on gallery to /gallery but the <h1>Gallery page</h1> does not show up anymore.
App.js
import React, { Component } from 'react';
import './App.css';
import NavigationBar from './components/navbar';
import About from './components/About';
import Home from './components/homepage';
import Gallery from './components/gallery';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
class App extends Component {
state = {};
render() {
return (
<Router>
<div className="App">
<NavigationBar />
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/gallery" component={Gallery} />
</Switch>
</div>
</Router>
);
}
}
export default App;
Homepage
import '../css/homepage.scss';
class Homepage extends Component {
state = {};
render() {
return (
<div>
<h1>Hello</h1>
</div>
);
}
}
export default Homepage;
About
class About extends Component {
state = {};
render() {
return <h1>About</h1>;
}
}
export default About;
Gallery
class gallery extends Component {
state = {};
render() {
return <h1>Gallery page</h1>;
}
}
export default gallery;
Nav code
import React, { Component } from 'react';
import Navbar from 'react-bootstrap/Navbar';
import Nav from 'react-bootstrap/Nav';
import { link } from 'react-router-dom';
import { NavLink } from 'react-router-dom';
import '../css/navbar.scss';
import $ from 'jquery';
import logo from '../images/logo.png';
class NavigationBar extends Component {
state = {};
render() {
return (
<Navbar fixed="top" className="navbarr" bg="light" expand="sm">
<Navbar.Brand
activeClassName="nav-link--active"
className="BrandLink"
href="/"
>
<img
alt=""
src={logo}
width="45"
height="30"
className="d-inline-block align-top"
/>
BRAND NAME HERE
</Navbar.Brand>
<Navbar.Toggle />
<Navbar.Collapse className="justify-content-end">
<Nav className="ml-auto">
<Nav.Link
className="NavLink"
activeClassName="nav-link--active"
href="/About"
>
About
</Nav.Link>
<Nav.Link
className="NavLink"
activeClassName="nav-link--active"
href="/Gallery"
>
Gallery
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
);
}
}
export default NavigationBar;
Try moving your default route to the end of routes. i.e.
import React, { Component } from 'react';
import './App.css';
import NavigationBar from './components/navbar';
import About from './components/About';
import Home from './components/homepage';
import Gallery from './components/gallery';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
class App extends Component {
state = {};
render() {
return (
<Fragment>
<div className="App">
<NavigationBar />
</div>
<Router>
<Switch>
<Route path="/about" component={About} />
<Route path="/gallery" component={Gallery} />
<Route path="/" component={Home} />
</Switch>
</Router>
</Fragment>
);
}
}
export default App;
The problem is with you Navbar components. Try this one:
import React, { Component } from "react";
import Navbar from "react-bootstrap/Navbar";
import Nav from "react-bootstrap/Nav";
import { Link } from "react-router-dom";
import "../css/navbar.scss";
import $ from "jquery";
import logo from "../images/logo.png";
class NavigationBar extends Component {
state = {};
render() {
return (
<Navbar fixed="top" className="navbarr" bg="light" expand="sm">
<Navbar.Brand activeClassName="nav-link--active" className="BrandLink">
<Link to="/">
<img
alt=""
src={logo}
width="45"
height="30"
className="d-inline-block align-top"
/>
BRAND NAME HERE
</Link>
</Navbar.Brand>
<Navbar.Toggle />
<Navbar.Collapse className="justify-content-end">
<Nav className="ml-auto">
<Nav.Link className="NavLink" activeClassName="nav-link--active">
<Link to="/about">About</Link>
</Nav.Link>
<Nav.Link className="NavLink" activeClassName="nav-link--active">
<Link to="/gallery">Gallery</Link>
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
);
}
}
export default NavigationBar;

Issues with Reach router Nested routes

i am having trouble with reach router nested routes, I am trying to navigate to / and render page2, but I am stuck on "/" homepage the same page when the route changes to //
<Appjs>
import React from "react";
import "./App.css";
import Homepage from "./Components/Homepage";
import Details from "./Components/Details";
function App() {
return (
<div>
<Router>
<Homepage path="/">
<Details path="details" />
</Homepage>
</Router>
</div>
);
}
export default App;
import React, { Component, useEffect, useState } from "react";
import styled, { isStyledComponent } from "styled-components";
import NavLink from "./NavLink";
import { Link } from "#reach/router";
const Homepage = () => {
const [users, setUsers] = useState([]);
return (
<React.Fragment>
<div className={"container"}>
<Styleddiv>
<h2>Select an Account</h2>
<div style={{ padding: 0 }}>
{Object.values(users).map((item) => (
<Link to={`details/${item.name}`}>
<img src={item.profilepicture} alt="Girl in a jacket"></img>
<span>{item.name}</span>
</Link>
))}
</div>
</Styleddiv>
</div>
</React.Fragment>
);
};
export default Homepage;
Am I missing something while structuring the routes inside the router, Kindly help me
So in Homepage If i click on any Link the route changes to /details but the details page fails to render
https://codesandbox.io/s/billowing-hill-j5gmy?file=/src/Homepage.js
Did you miss your Router import on your App.js file?
import React from "react";
import { Router, Link } from "#reach/router";
import Homepage from "./Homepage";
import Details from "./Details";
export default function App() {
return (
<div>
<nav>
<Link to="/">Home</Link>
<Link to="dashboard">Detail</Link>
</nav>
<Router>
<Homepage path="/" />
<Details path="dashboard" />
</Router>
</div>
);
}
Edit: Code Sand Box
This is how I use nested routes
Code sandbox
In order to nest routes you need to place them in the child component of the route.
The render prop is used instead of component because it stops the inline functional component from being remounted every render, see explanation.
The match object contains the information about how a route matched the URL, so we can have a nested route using the url property which gives us the matched portion of the URL, see explanation.

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

Resources