I'm trying a double nested for loop but it's not quite unraveling how I predict, advice? am i not allowed to call a double for loop in function? Essentially it suppose to create a navbar from an array of objects i.e [{name:['Jonathan,'bob']},{dob:['may 21','june 22']}]
import React,{Component} from "react";
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import NavDropdown from 'react-bootstrap/NavDropdown';
export function navBar(content){
return(
<Navbar bg="light" expand="lg">
<Container>
<Navbar.Brand href="#home">React-Bootstrap</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
{content.map((cont) => {
<NavDropdown title="Dropdown" id={Object.keys(cont)[0]}>
{
Object.values(cont).map((key)=>{<a href={"http://localhost:3000/"+key}>{key}</a>})
}
</NavDropdown>
})}
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
);
}
You are not returning from your map functions:
<Nav className='me-auto'>
{content.map((cont) => {
// from here
<NavDropdown title='Dropdown' id={Object.keys(cont)[0]}>
{Object.values(cont).map((key) => {
// and from here
<a href={'http://localhost:3000/' + key}>{key}</a>;
})}
</NavDropdown>;
})}
</Nav>
Solution:
<Nav className='me-auto'>
{content.map((cont) => {
return (<NavDropdown title='Dropdown' id={Object.keys(cont)[0]}>
{Object.values(cont).map((key) => {
return <a href={'http://localhost:3000/' + key}>{key}</a>;
})}
</NavDropdown>);
})}
</Nav>;
Since you are using arrow functions, you can omit the curly brackets and the return:
<Nav className='me-auto'>
{content.map((cont) => (
<NavDropdown title='Dropdown' id={Object.keys(cont)[0]}>
{Object.values(cont).map((key) => (
<a href={'http://localhost:3000/' + key}>{key}</a>
))}
</NavDropdown>
))}
</Nav>;
Also, the content parameter of your navBar is not an array but the props object, so you shouldn't be able to call map on it.
If you use navBar like: <navBar content={...}/>, you have to update its code like:
export function navBar({ content }){
// ...
}
Related
I want to update the text color of the content inside the bar, but for some reason it doesn't work.
What I've tried so far: Link a css stylesheet (it doesn't work for some reason)
inline style (it only works for the company name and the cart, not for the user's name)
Here is the code to my header:
import React from 'react'
import { Route } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { LinkContainer } from 'react-router-bootstrap'
import { Navbar, Nav, Container, NavDropdown } from 'react-bootstrap'
import SearchBox from './SearchBox'
import { logout } from '../actions/userActions'
import '../index.css' //changes in index.css do not update in header.js
const Header = () => {
const dispatch = useDispatch()
const userLogin = useSelector((state) => state.userLogin)
const { userInfo } = userLogin
const logoutHandler = () => {
dispatch(logout())
}
return (
<header>
<Navbar style={{ backgroundColor: '#0a4275' }} variant="light" expand='lg' collapseOnSelect >
<Container >
<LinkContainer to='/'>
<Navbar.Brand><span style={{ color: 'white' }}> CFM Système</span></Navbar.Brand>
</LinkContainer>
<Navbar.Toggle aria-controls='basic-navbar-nav' />
<Navbar.Collapse id='basic-navbar-nav'>
<Route render={({ history }) => <SearchBox history={history} />} />
<Nav className='ml-auto'>
<LinkContainer to='/cart'>
<Nav.Link>
<span style={{ color: 'white' }}> <i className='fas fa-shopping-cart'></i> Panier</span>
</Nav.Link>
</LinkContainer>
{userInfo ? (
<NavDropdown title={userInfo.name} id='username'>
<LinkContainer to='/profile'>
<NavDropdown.Item>Profil</NavDropdown.Item>
</LinkContainer>
<NavDropdown.Item onClick={logoutHandler}>
Se déconnecter
</NavDropdown.Item>
</NavDropdown>
) : (
<LinkContainer to='/login'>
<Nav.Link>
<i className='fas fa-user'></i> Se connecter
</Nav.Link>
</LinkContainer>
)}
{userInfo && userInfo.isAdmin && (
<NavDropdown title='Admin' id='adminmenu'>
<LinkContainer to='/admin/userlist'>
<NavDropdown.Item>Utilisateurs</NavDropdown.Item>
</LinkContainer>
<LinkContainer to='/admin/productlist'>
<NavDropdown.Item>Produits</NavDropdown.Item>
</LinkContainer>
<LinkContainer to='/admin/orderlist'>
<NavDropdown.Item>Commandes</NavDropdown.Item>
</LinkContainer>
</NavDropdown>
)}
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
</header>
)
}
export default Header
I'm clearly missing something, but I'm out of solutions?
I changed my NavBarDesktop to add props in super like below. My HomePage shows but if I click on About Us or any other page, I get a blank page. I also added my HomePage Code below as well. I am not sure why it does this. If I take const MyView our the pages work but there is no categories in NavDropdown.
NavMenuDesktop
class NavMenuDesktop extends React.Component{
constructor(props){
super(props);
}
render(){
const CatList = this.props.data;
const MyView = CatList.map((CatList,i)=>{
return <div key={i.toString()}>
<NavDropdown.Item href="">{CatList.category_name}</NavDropdown.Item>
</div>
});
return(
<Fragment>
<Navbar bg="light" expand="lg" sticky="top">
<Container>
<Navbar.Brand href="/"><img src={Logo} className="nav-logo" /></Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" className="nav-toggler" ><i className="fa fa-bars"></i></Navbar.Toggle>
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Nav.Link href="/">Home</Nav.Link>
<Nav.Link href="/about">About Us</Nav.Link>
<NavDropdown title="Shop" id="basic-nav-dropdown" renderMenuOnMount={true}>
{MyView}
</NavDropdown>
<Nav.Link href="/contact">Contact</Nav.Link>
<NavDropdown title="My Account" id="collasible-nav-dropdown" renderMenuOnMount={true}>
<NavDropdown.Item href="/login"><i className="fa fa-sign-in-alt p-2 colorred"></i>Login</NavDropdown.Item>
<NavDropdown.Item href="#action/3.2"><i className="fa fa-user-plus p-2 colorred"></i>Register</NavDropdown.Item>
</NavDropdown>
<ul className="inline justify-content-right">
<li><Nav.Link href="/favorites"><i className="fa fa-heart fa-md text-secondary"></i>
<sup><span className="badge text-white bgred fa-md">5</span></sup>
</Nav.Link></li>
<li><Nav.Link href="/cart"><i className="fa fa-shopping-cart fa-md text-secondary"></i>
<sup><span className="badge text-white bgred fa-md">5</span></sup>
</Nav.Link>
</li>
</ul>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
</Fragment>
)
}
}
export default NavMenuDesktop;
HomePage
import React, { Component, Fragment } from 'react';
import { Container } from 'react-bootstrap';
import AppURL from '../api/AppURL';
import AppRoute from '../route/AppRoute';
import FeaturedProducts from '../components/home/FeaturedProducts';
import Categories from '../components/home/Categories';
import Collection from '../components/home/Collection';
import NewArrival from '../components/home/NewArrival';
import HomeTop from '../components/home/HomeTop';
import NavMenuDesktop from '../components/common/NavMenuDesktop';
import FooterDesktop from '../components/common/FooterDesktop'
import axios from 'axios';
class HomePage extends Component {
constructor(){
super();
this.state ={
MenuData:[]
}
}
componentDidMount(){
window.scroll(0,0);
this.GetVisitorDetails();
axios.get(AppURL.CategoryInfo).then(response =>{
this.setState({MenuData:response.data});
}).catch(error=>{
});
}
GetVisitorDetails = ()=>{
axios.get(AppURL.VisitorDetails).then().catch()
}
render() {
return (
<Fragment>
<NavMenuDesktop data={this.state.MenuData}/>
<HomeTop />
<Container fluid={"true"}>
<Categories />
<NewArrival />
<FeaturedProducts />
<Collection />
<FooterDesktop/>
</Container>
</Fragment>
)
}
}
export default HomePage;
in constructor use super(props) then write the myView const in componentDidMount() function like this:
componentDidMount(){
const CatList = this.props.data;
const MyView = CatList.map((CatList,i)=>{
return <div key={i.toString()}>
<NavDropdown.Item href="">{CatList.category_name}</NavDropdown.Item>
</div>
});
window.scroll(0,0);
this.GetVisitorDetails();
axios.get(AppURL.CategoryInfo).then(response =>{
this.setState({MenuData:response.data});
}).catch(error=>{
});
}
I did the navbar offcanvas across all breakpoints using the attribute expand={false} like the image below.
However i want the navbar items to be like the normal navigation on (min-width: 992px) OR expand="lg" like the image below. Im using reactrouter v6 and react-bootstrap.
Below is my code and also here is the working sandbox code https://codesandbox.io/.
import React, { useState } from "react";
import { Container, Navbar, Nav, Offcanvas } from "react-bootstrap";
import { NavLink, Outlet } from "react-router-dom";
const NavbarContent = () => {
const [isOpen, setOpen] = useState(false);
return (
<>
<Navbar
expanded={isOpen}
expand={false}
bg="light"
fixed="top"
className="bg-white text-the-primary bg-gradient shadow py-3"
>
<Container>
<Navbar.Brand href="/">
<span className="d-block fs-1">Offcanvas</span>{" "}
</Navbar.Brand>
<Navbar.Toggle
aria-controls="offcanvasNavbar"
onClick={() => setOpen(isOpen ? false : "expanded")}
/>
<Navbar.Offcanvas
id="offcanvasNavbar"
aria-labelledby="offcanvasNavbarLabel"
placement="end"
>
<Offcanvas.Header
closeButton
className="justify-content-end"
onClick={() => setOpen(false)}
></Offcanvas.Header>
<Offcanvas.Body>
<Nav className="justify-content-end flex-grow-1 pe-0">
<NavLink to="/" onClick={() => setOpen(false)}>
Home
</NavLink>
<NavLink to="/About" onClick={() => setOpen(false)}>
About
</NavLink>
</Nav>
</Offcanvas.Body>
</Navbar.Offcanvas>
</Container>
</Navbar>
<Outlet />
</>
);
};
export default NavbarContent;
I'm not sure if I missed something on useState and expand attribute of the navbar.
Set the expand break point to large using the command
<Navbar
expanded={isOpen}
expand='lg'
...
/>
Works for me
I'm using React Context to store data into sessionstorage for the purposes of logging in and out. I'm saving three things: IDContext for saving the user's ID, UserNameContext for saving the user's username, and AdminContext to simply see if the logged in user is an admin or not. I want to display the logged in user's username on the navigation bar such as (Welcome, {user}) but instead it just displays as (Welcome, {}). I checked the sessionstorage via the developer tools, and it shows
username:""user""
So why exactly does it show up blank on the navigation bar, am I not grabbing the data correctly?
auth.js:
import { createContext, useContext } from "react";
export const UserNameContext = createContext();
export const IDContext = createContext();
export const AdminContext = createContext();
export function useUserName() {
return useContext(UserNameContext);
}
export function useID() {
return useContext(IDContext);
}
export function useAdmin() {
return useContext(AdminContext);
}
navbar.js:
import React from "react";
import { Navbar, Nav, Container } from "react-bootstrap";
import { Link } from "react-router-dom";
import { useID, useUserName, useAdmin } from "../context/auth";
function Navigation(props) {
const { IDTokens } = useID();
const { usernameTokens } = useUserName();
const { adminTokens } = useAdmin();
function adminNav() {
return (
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Link to="#">Placeholder</Link>
</Nav>
<Nav>
<Link to={`/${usernameTokens}`}>Welcome, {usernameTokens}</Link>
<Link to="/logout">Log Out</Link>
</Nav>
</Navbar.Collapse>
)
}
function loggedInNav() {
return (
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Link to="#">Placeholder</Link>
</Nav>
<Nav>
<Link to={`/${usernameTokens}`}>Welcome, {usernameTokens}</Link>
<Link to="/logout">Log Out</Link>
</Nav>
</Navbar.Collapse>
)
}
function guestNav() {
return(
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Link to="#">Placeholder</Link>
</Nav>
<Nav>
<Link to="/register">Register</Link>
<Link to="/login">Login</Link>
</Nav>
</Navbar.Collapse>
)
}
return (
<Navbar bg="primary" variant="dark" expand="md">
<Container>
<Link to="/">Flaskagram</Link>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
{IDTokens && adminTokens ? (
adminNav()
) : IDTokens ? (
loggedInNav()
) : (
guestNav()
)}
</Container>
</Navbar>
)
}
export default Navigation;
You don't need three separate contexts for storing those 3 pieces of information. To make your user object accessible from anywhere in your app, add this line inside App.js (at the beginning of the App function):
const [user, setUser] = useState();
Make sure the useState hook is imported in App.js, as well as UserContext from wherever you will define your context (in your case, I believe it is auth.js).
Then, wrap all the jsx elements that are returned from App.js with the context provider like so:
export default function App() {
const [user, setUser] = useState();
// any other code you might have here
return (
<UserContext.Provider value={{ user, setUser }}>
// all your app's components here
</UserContext.Provider>
);
}
In auth.js, this is all you need:
import React from "react";
const UserContext = React.createContext();
export default UserContext;
Wherever you set the user object (most likely on your login page), just use the following line to access the setUser function (and don't forget to import UserContext):
const { setUser } = useContext(UserContext);
Now, in navbar.js:
import React, { useContext } from "react";
import { Navbar, Nav, Container } from "react-bootstrap";
import { Link } from "react-router-dom";
import UserContext from "../context/auth";
function Navigation() {
const {
user: { username, isAdmin },
} = useContext(UserContext);
function adminNav() {
return (
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Link to="#">Placeholder</Link>
</Nav>
<Nav>
<Link to={`/${username}`}>Welcome, {username}</Link>
<Link to="/logout">Log Out</Link>
</Nav>
</Navbar.Collapse>
);
}
function loggedInNav() {
return (
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Link to="#">Placeholder</Link>
</Nav>
<Nav>
<Link to={`/${username}`}>Welcome, {username}</Link>
<Link to="/logout">Log Out</Link>
</Nav>
</Navbar.Collapse>
);
}
function guestNav() {
return (
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Link to="#">Placeholder</Link>
</Nav>
<Nav>
<Link to="/register">Register</Link>
<Link to="/login">Login</Link>
</Nav>
</Navbar.Collapse>
);
}
return (
<Navbar bg="primary" variant="dark" expand="md">
<Container>
<Link to="/">Flaskagram</Link>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
{username && isAdmin
? adminNav()
: username
? loggedInNav()
: guestNav()}
</Container>
</Navbar>
);
}
export default Navigation;
In order for this implentation to work, when you log the user in, the user object must have the properties of isAdmin and username set so that they can be accessed in the navbar. The isLoggedIn property is unnecessary because if the username property isn't null, it means that a user must be logged in.
Well, if you already have that item in your localstorage, you can just grab it using useEffect hook upon loading.
like this for example:
useEffect(() => {
const cachedUserName = JSON.parse(localStorage.getItem('username'));
if (cachedUserName ) {
setUserName(cachedUserName);
}
else {
...your logic
}
}, [setUserName]);
I want to simply highlight the tab selected from the NavBar. I had used the Navbar Component of React-bootstrap and used the state to change the bgColor and textColor of the selected tab. But it is still NOT working? Any corrections?
import React,{useState} from 'react';
import { Navbar,Container, Nav } from "react-bootstrap"
import { LogOut } from "./LogOut"
const NavbarComponent = () => {
const [bgcolor, setBgcolor] = useState('black');
const [textcolor, setTextcolor] = useState('white');
function handleHighlightTab() {
setBgcolor('white');
setTextcolor('black');
}
return (
<>
<Navbar bg="dark" variant="dark" fixed='top' className='nav-pills'>
<Container>
<Navbar.Brand href="/">Verticals</Navbar.Brand>
<Nav className="me-auto">
<Nav.Link href="/grocery" onSelect={handleHighlightTab} style={{backgroundColor:{bgcolor},color:{textcolor} }} >Grocery</Nav.Link>
<Nav.Link href="/fashion" onSelect={handleHighlightTab} style={{backgroundColor:{bgcolor},color:{textcolor} }} >Fashion</Nav.Link>
<Nav.Link href="/footwear" onSelect={handleHighlightTab} style={{backgroundColor:{bgcolor},color:{textcolor} }}>Footwear</Nav.Link>
</Nav>
<LogOut />
</Container>
</Navbar>
</>
)
}
export default NavbarComponent;