I have two navbars in my site. One is only displayed on small screens with a media query which is the one I am having issues with. I have a react context that controls the visibility of both navs with the same boolean variable when a slideshow is displayed. When the slide show is displayed I want to hide the navs. The large nav has this functionality, but the small nav never shows. Before adding this react context the navbar would display as normal but now it is never displayed.
small navbar render:
render() {
return (
<div className="container-fluid">
<div id="initialImage">
<div className="d-fixed d-md-none">
<DisplayContext.Consumer>
{(context) =>
context.state.isNavVisibile ? (
<nav className="navbar bg-dark navbar-dark fixed-top">
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarToggleContent"
aria-controls="navbarToggleContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span></span>
<span></span>
<span></span>
</button>
<div
className="collapse navbar-collapse"
id="navbarToggleContent"
>
<ul className="navbar-nav">
<li className="nav-item">
<a
className="nav-link text-white font-weight-bold"
href="#vintage"
>
Shop Vintage
</a>
</li>
<li className="nav-item">
<a
className="nav-link text-white font-weight-bold"
href="#e"
>
Shop Euiubi
</a>
</li>
<li className="nav-item">
<a
className="nav-link text-white font-weight-bold"
href="#about"
>
A Message from the Creator
</a>
</li>
<li className="nav-item">
<a
className="nav-link text-white font-weight-bold"
href="#"
>
Contact
</a>
</li>
</ul>
</div>
</nav>
) : null
}
</DisplayContext.Consumer>
</div>
<Navigation />
<div id="titles" className="clearfix greeting"></div>
<ScrollAnimation />
</div>
</div>
);
}
}
Display Context:
export const DisplayContext = createContext();
export class ContextProvider extends Component {
state = {
isNavVisible: true,
};
render() {
return (
<DisplayContext.Provider
value={{
state: this.state,
hideNav: () =>
this.setState({ isNavVisible: !this.state.isNavVisible }),
}}
>
{this.props.children}
</DisplayContext.Provider>
);
}
}
on click handler to open and close slideshow
toggleSlideVisibility = () => {
const dcontext = this.context;
dcontext.hideNav();
this.setState({ slidesVisible: !this.state.slidesVisible });
};
Related
My Main Motto is to use the Dark mode feature. In this case i'm Taking a Prop from app.js and assigning it to a state pMode and i am trying to change the class of the navbar using the setPmode method which is used as Ternary in onclick of Input tag and i am getting error of
Error : Too many re-renders. React limits the number of renders to prevent an infinite loop.
import React,{useState} from 'react';
export default function Navbar(props) {
let [pMode,setPmode] = useState(props.Mode);
return (
<>
<nav className={`navbar navbar-expand-lg navbar-${pMode} bg-${pMode}`}>
<div className="container-fluid">
<a className="navbar-brand" href="/">Navbar</a>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse " id="navbarNav">
<ul className="navbar-nav mx-auto">
<li className="nav-item">
<a className="nav-link active" aria-current="page" href="/">Home</a>
</li>
<li className="nav-item">
<a className="nav-link" href="/">Features</a>
</li>
<li className="nav-item">
<a className="nav-link" href="/">Pricing</a>
</li>
</ul>
<div className="form-check form-switch">
<input className="form-check-input" onClick={pMode=== "light"? setPmode("dark") : setPmode("light")} type="checkbox" role="switch" id="flexSwitchCheckDefault" />
<label className="form-check-label" htmlFor="flexSwitchCheckDefault">{pMode} mode</label>
</div>
</div>
</div>
</nav>
</>
);
}
This arrow function help with Infinite re-rendering.
onClick={()=>pMode=== "light"? setPmode("dark") : setPmode("light")}
import React,{useState} from 'react';
export default function Navbar(props) {
let [pMode,setPmode] = useState(props.Mode);
return (
<>
<nav className={`navbar navbar-expand-lg navbar-${pMode} bg-${pMode}`}>
<div className="container-fluid">
<a className="navbar-brand" href="/">Navbar</a>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse " id="navbarNav">
<ul className="navbar-nav mx-auto">
<li className="nav-item">
<a className="nav-link active" aria-current="page" href="/">Home</a>
</li>
<li className="nav-item">
<a className="nav-link" href="/">Features</a>
</li>
<li className="nav-item">
<a className="nav-link" href="/">Pricing</a>
</li>
</ul>
<div className="form-check form-switch">
<input className="form-check-input" onClick={()=>pMode=== "light"? setPmode("dark") : setPmode("light")} type="checkbox" role="switch" id="flexSwitchCheckDefault" />
<label className="form-check-label" htmlFor="flexSwitchCheckDefault">{pMode} mode</label>
</div>
</div>
</div>
</nav>
</>
);
}
You need to slightly modify the onClick function
<input
className="form-check-input"
onClick={() => setPMode((prev) => prev === 'light' ? 'dark' : 'light')}
type="checkbox"
role="switch"
id="flexSwitchCheckDefault" />
The issue earlier was that your onClick was a function call instead of a function. So every time the component rendered, the function call was executed which caused a change in state and then a re render. Also when your new state depends on previous state, it is recommended to use a function to setState
onClick={()=>{pMode=== "light"? setPmode("dark") : setPmode("light")}}
If you want to execute code inside onclick, you should use the arrow function.
This code worked the first time for login, but then when i logged out, it successfully did so but instead of changing the logout button to login again, after refreshing the page it just removed my name and pfp from the top of the navbar with the logout button still there, what changes should i make here to make it work?
here's a picture of the page before logout
here's a picture of the page after logout and refresh
import { NavLink } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { auth, signInWithGoogle } from '../Firebase';
const Navbar = () => {
// To get a state of addItems, use name of the file not the function
const state = useSelector((state) => state.addItem);
const logOut = async () => {
await auth.signOut().then(console.log("signed out."));
localStorage.clear(auth);
}
return (
<div>
<nav className="navbar navbar-expand-lg navbar-light bg-light py-3 shadow-sm">
<div className="container">
<NavLink className="navbar-brand fw-bold fs-4" to="/">DUST</NavLink>
<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 mx-auto mb-2 mb-lg-0">
<li className="nav-item">
<NavLink className="nav-link active" aria-current="page" to="/">HOME</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to="/products">PRODUCTS</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to="/about">ABOUT</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link" to="/contact">CONTACT</NavLink>
</li>
</ul>
<div className="buttons">
{localStorage.getItem("name") === "" ? (
<button className="btn btn-outline-dark ms-3" onClick={signInWithGoogle}>
<i className='fa fa-sign-in me-1'></i> LOGIN
</button>
) : (
<>
<div className='container'>
<NavLink to="/cart" className="btn btn-outline-dark ms-2 me-5">
<i className='fa fa-shopping-cart me-1'></i>
{state?.length}
</NavLink>
<h4 className="lead">{localStorage.getItem("name")}</h4>
<img src={localStorage.getItem("profilePic")} alt="Profile" className='img-fluid img-responsive rounded-circle ms-2' style={{ height:50, width:50 }} />
<button className="btn btn-outline-dark ms-5" onClick={logOut}> {/*localstorage clear*/}
<i className='fa fa-sign-out me-1'></i> LOGOUT
</button>
</div>
</>
)
}
</div>
</div>
</div>
</nav>
</div>
);
}
export default Navbar;
The localStorage.getItem("test") === "" will always be false because if the key doesn't exist then getItem() returns null. Try:
// without === ""
localStorage.getItem("name") ? (...) : (...)
You can however read user's name directly from Firebase authentication:
auth.currentUser?.displayName
I saw the article of React on the website. However, while I implement conditional render function as follow :
export class Root extends React.Component {
constructor(props) {
super(props);
};
log_out = () => { };
render() {
var dropdown_menu;
firebase.auth().onAuthStateChanged((user) => {
// Check user login
if (user) {
console.log("start render root with user login");
dropdown_menu = <div id="dynamic-menu" class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class='dropdown-item'>{user.email}</a>
<a class='dropdown-item' id='logout-btn' onClick={() => this.log_out()}>Logout</a>
</div>;
} else {
console.log("start render root without user login")
dropdown_menu = <div id="dynamic-menu" class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="./signin.html">Login</a>
</div>;
}
});
return (
<div>
<nav class="navbar navbar-expand-md fixed-top navbar-dark bg-dark"> {/* nav is for upper bar of functional buttons */}
<a class="navbar-brand" href="index.html">Simple Forum</a>
<button class="navbar-toggler p-0 border-0" type="button" data-toggle="offcanvas"> {/* RWD navbar toggler */}
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse offcanvas-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Account</a>
{dropdown_menu}
</li>
</ul>
</div>
</nav>
<div id="custom-alert"></div>
<main role="main" class="container">
<div class="d-flex align-items-center p-3 my-3 text-white-50 bg-purple rounded box-shadow">
<img class="mr-3" src="img/bootstrap.svg" alt="" width="48" height="48"/>
<div class="lh-100">
<h6 class="mb-0 text-white lh-100">Lab 07 Simple Forum</h6>
<small>Software Studio 2022 Spring</small>
</div>
</div>
<div id="post_list">
</div>
<div class="my-3 p-3 bg-white rounded box-shadow">
<h5 class="border-bottom border-gray pb-2 mb-0">New Post</h5>
<textarea class="form-control" rows="5" id="comment"></textarea>
<div class="media text-muted pt-3">
<button id="post_btn" type="button" class="btn btn-success" onClick={() => {post_handler()}}>Submit</button>
</div>
</div>
</main>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="js/offcanvas.js"></script>
</div>
);
}
}
my dropdown_menu is ignore by Chrome. To be more specify, the console log did show "start render root without user login", however the Chrome Element completely ignore {dropdown_menu}.
You have to set a user as a state in componentDidMount (make it null by initial) and render it like this
state = { user: null}
componentDidMount {
firebase.auth().onAuthStateChanged((user) => this.setState({user})
}
...
<div class="navbar-collapse offcanvas-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Account</a>
{this.state.user ? <div id="dynamic-menu" class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class='dropdown-item'>{user.email}</a>
<a class='dropdown-item' id='logout-btn' onClick={() => this.log_out()}>Logout</a>
</div> : <div id="dynamic-menu" class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="./signin.html">Login</a>
</div>}
</li>
</ul>
</div>
I'm trying to code one sticky bar and one fixed navbar right underneath the sticky with Bootstrap 5. I created one Navbar file with the sticky navbar code in it, and one FixedNav file with my fixed navbar code in it and brought in the Fixed navbar component inside my sticky navbar component. '
This is what it currently looks like, I want the opposite, yellow Nav on the bottom of white
At first, the fixed navbar was overlapping the sticky, and after researching I found out that setting the body with a padding-top:50px would fix it. However, I noticed that the solution only makes the sticky nav bar long enough to show below the fixed navbar, so now the fixed navbar is on top of the sticky navbar. How do I make it so that the sticky navbar is ON TOP of the fixed navbar?
There is another navbar called LogIn navbar which renders a new navbar once the user is logged in (wont be focusing on that, in case anyone gets confused with the ternary statement where I bring in the fixed nav component)
import React from "react";
import { connect } from "react-redux";
import { logout } from "../store";
import Fixed from "./fixedNav";
import LoginNav from "./LoginNav";
//temporary navBar without loggedIn function/difference
const tempUserId = 1;
const Navbar = ({ handleClick, isLoggedIn }) => (
<div>
<div>
<nav
className="navbar sticky-top navbar-light bg-light"
style={{ backgroundColor: "#F0FFFF" }}
>
<div>
<form className="d-flex">
<input
className="form-control me-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
<button className="btn btn-sm btn-outline-secondary" type="submit">
Search
</button>
</form>
</div>
<div>
<a href="/" className="navbar-brand" />
Grace Barker
</div>
<div>
<ul className="nav justify-content-end">
<li className="nav-item">
<a className="nav-link active" aria-current="page" href="/">
Contact Us
</a>
</li>
<li className="nav-item">
<a className="nav-link active" aria-current="page" href="/cart">
Cart
</a>
</li>
</ul>
</div>
</nav>
{isLoggedIn ? (
<LoginNav handleClick={handleClick} isLoggedIn={isLoggedIn} />
) : (
<Fixed handleClick={handleClick} isLoggedIn={isLoggedIn} />
)}
</div>
</div>
);
FIXED NAVBAR CODE
import React from "react";
import { Link } from "react-router-dom";
const Fixed = ({ handleClick, isLoggedIn }) => (
<div>
<nav
className=" navbar fixed-top navbar-expand-lg"
style={{ backgroundColor: "#FFF8DC" }}
>
<div className="collapse navbar-collapse " id="navbarSupportedContent">
<ul className="nav nav-tabs">
<li className="nav-item ">
<Link to="/home" className="nav-link ">
Home
</Link>
</li>
<li className="nav-item dropdown">
<a
className="nav-link dropdown-toggle "
data-bs-toggle="dropdown"
href="/"
role="button"
aria-expanded="false"
>
Dogs
</a>
<ul className="dropdown-menu">
<li>
<a className="dropdown-item " href="/dogs">
Available Dogs
</a>
</li>
<li>
<a className="dropdown-item " href="/">
Featured Dogs
</a>
</li>
</ul>
</li>
<li className="nav-item">
<Link to="/AboutUs" className="nav-link ">
About Us
</Link>
</li>
</ul>
</div>
<div>
<ul className="nav justify-content-end">
<li className="nav-item">
<a className="nav-link active " aria-current="page" href="/users">
Users
</a>
</li>
<li className="nav-item">
{isLoggedIn ? (
<a
className="nav-link active "
aria-current="page"
href="/home"
onClick={handleClick}
>
LogOut
</a>
) : (
<a className="nav-link active " aria-current="page" href="/login">
Login
</a>
)}
</li>
</ul>
</div>
</nav>
</div>
);
export default Fixed;
CSS
body {
font-family: "Courier New", Courier, monospace;
padding-top: 50px;
}
CSS position fixed is similar to position absolute, it hides everything under it. You can set z-index value to it to change its layer order. If you want to show the sticky nav bar just under the fixed one you have to give it a top value same as the height of fixed nav bar.
#fixed-nav {
position: fixed;
top: 0;
height: 72px;
z-index: 100;
}
#sticky-nav {
position: sticky;
top: 72px; // same as the height of fixed nav bar.
z-index: 200;
}
I have created this Navbar using boostsrap 4, but i want it to get collapse when i click on the link,
Any way to do this? Thanks.
please help me i'm stuck here.
import moon from '../Images/moon.ico'
import { NavLink } from 'react-router-dom'
const NavBar = () => {
return(
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
<NavLink to='/' className="navbar-brand"><img src={moon} alt="logo" className="logo-img"/></NavLink>
<button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
<li className="nav-item">
<NavLink to="/" className="nav-link">Home</NavLink>
</li>
<li className="nav-item">
<NavLink to="/about" className="nav-link">About</NavLink>
</li>
<li className="nav-item">
<NavLink to='/skill' className="nav-link">Skills</NavLink>
</li>
<li className="nav-item">
<NavLink to="/project" className="nav-link">Projects</NavLink>
</li>
</ul>
</div>
</nav>
)
}
export default NavBar```