React Ternary Operator Prevent Repeating Code with Styled components? - reactjs

So I'm using styled components and found the only way to trigger my function is with a ternary operator that wraps my entire navbar component. The problem is I have to recopy the entire component code into the : statement which basically means I'm writing my nav component code twice just to get the ternary to work properly.
Is there a way to not repeat it and write the ternary with the least amount of code?
So here's my code issue
return (
<>
// If scroll is true, I want to add this active prop onto my <Nav>
{scroll ? (
<Nav active click={click}>
<NavbarContainer>
<NavLogo to="/" onClick={closeMobileMenu}>
<NavIcon />
EXPLOR
</NavLogo>
<MobileIcon onClick={handleClick}>
{click ? <FaTimes /> : <FaBars />}
</MobileIcon>
<NavMenu onClick={handleClick} click={click}>
<NavItem>
<NavLinks to="/">Home</NavLinks>
</NavItem>
<NavItem>
<NavLinks to="/images">Images</NavLinks>
</NavItem>
<NavItem>
<NavLinks to="/products">Products</NavLinks>
</NavItem>
</Nav>
:
// If the scroll is false, I remove the active prop from my nav
(
<Nav click={click}>
<NavbarContainer>
<NavLogo to="/" onClick={closeMobileMenu}>
<NavIcon />
EXPLOR
</NavLogo>
<MobileIcon onClick={handleClick}>
{click ? <FaTimes /> : <FaBars />}
</MobileIcon>
<NavMenu onClick={handleClick} click={click}>
<NavItem>
<NavLinks to="/">Home</NavLinks>
</NavItem>
<NavItem>
<NavLinks to="/images">Images</NavLinks>
</NavItem>
<NavItem>
<NavLinks to="/products">Products</NavLinks>
</NavItem>
</Nav>
}
</>
The whole point is so I can trigger this active prop from my styled component
background: ${({ active }) => (active ? "#141414" : "transparent")};
But as you can see I had to copy my entire component code twice because the <Nav> that has the active prop wraps around my entire code.
Is there an easier way to toggle the active prop with styled components without having to recopy my entire navbar in the : or statement?

Assuming active is a booelan you can smply set active={scroll } like so
<Nav active={scroll} click={click}>
.....
</Nav>

Related

React : Error: Too many re-renders. React limits the number of renders to prevent an infinite loop

Im currently trying to import my Navbar into a new project. I created a Navbar using the state hook.
export default function Heading() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<Navbar color="light" fixed="top" light expand="md">
<NavbarBrand href="/">reactstrap</NavbarBrand>
<NavbarToggler onclick={setIsOpen(!isOpen)} />
<Collapse isOpen={isOpen} navbar>
<Nav className="me-auto" navbar>
<NavItem>
<NavLink href="/components/">Components</NavLink>
</NavItem>
<NavItem>
<NavLink href="https://github.com/reactstrap/reactstrap">
GitHub
</NavLink>
</NavItem>
<UncontrolledDropdown inNavbar nav>
<DropdownToggle caret nav>
Options
</DropdownToggle>
<DropdownMenu end>
<DropdownItem>Option 1</DropdownItem>
<DropdownItem>Option 2</DropdownItem>
<DropdownItem divider />
<DropdownItem>Reset</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
</Nav>
<NavbarText>Simple Text</NavbarText>
</Collapse>
</Navbar>
</div>
);
}
I am importing this in my App.tsx like this
import Heading from "./modules/Heading";
export default function App() {
return (
<div className="App">
<Heading/>
</div>
);
}
But im getting this error
Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
Does anyone know how to fix this?
The issue is highly likely with the onclick in your NavbarToggler component.
Usually in React, onclick event handler usually takes in a FUNCTION, not a FUNCTION CALL. Therefore, you should change to
<NavbarToggler onClick={() => setIsOpen(currentState => !currentState)} />
This small change creates an arrow function that will do the same as before. However, the difference is that this is only a function definition, meaning it is not called yet (and is just existing)
It's missing an arrow function in NavbarToggler onClick Event . I guess will solve the problem

Toggling Images for Active Links with React.js

I am currently trying to learn React.js for a school project and am having trouble with toggling images in combination with active links (I have searched high and low for a tutorial with no avail). My site is going to look similar to the old time Kingdom Hearts 1 menu theme; the Navbar looks like the following image.
As shown in the above image, the home page is hard-coded to be "active." What I need help with is making each link appear in this "active" state when selected/active. When a user clicks on one of the NavLinks, the image should go from grey to black/orange. When a link is not selected (or inactive), the image should go from black/orange back to grey. Active/selected links should also have black text while inactive links have grey. So far, all I have found out is how to toggle a singular class but not multiple. Overall, I really don't know how to go about this at all. How do I toggle one NavLink active and change its image while also changing all other NavLinks to inactive, changing their images as well? Any help would be much appreciated. I have the following code for my Navbar so far:
export class NavMenu extends Component {
static displayName = NavMenu.name;
constructor(props) {
super(props);
this.toggleNavbar = this.toggleNavbar.bind(this);
this.state = {
collapsed: true
};
}
toggleNavbar() {
this.setState({
collapsed: !this.state.collapsed
});
}
render() {
return (
<Navbar
fixed="bottom"
className="navbar-expand-sm navbar-toggleable-sm ng-white border-top mb-3"
light
>
<NavbarToggler onClick={this.toggleNavbar} className="mr-2" />
<Collapse
className="d-sm-inline-flex flex-sm-row-reverse"
isOpen={!this.state.collapsed}
navbar
>
<ul className="navbar-nav mr-auto">
<NavItem>
<NavLink
tag={Link}
id="navHome"
className="text-dark active"
to="/"
>
<img
src="/Images/NLUnactiveImg.png"
alt="Unactive Link Image"
height="45"
width="45"
hidden
/>
<img
src="/Images/NLActiveImg.png"
alt="Active Link Image"
height="45"
width="45"
/>
Home
</NavLink>
</NavItem>
<NavItem>
<NavLink
tag={Link}
d="navResume"
className="text-dark inactive"
to="/resume"
>
<img
src="/Images/NLUnactiveImg.png"
alt="Unactive Link Image"
height="45"
width="45"
/>
<img
src="/Images/NLActiveImg.png"
alt="Active Link Image"
height="45"
width="45"
hidden
/>
Resume
</NavLink>
</NavItem>
<NavItem>
<NavLink
tag={Link}
d="navContact"
className="text-dark inactive"
to="/contact"
>
<img
src="/Images/NLUnactiveImg.png"
alt="Unactive Link Image"
height="45"
width="45"
/>
<img
src="/Images/NLActiveImg.png"
alt="Active Link Image"
height="45"
width="45"
hidden
/>
Contact
</NavLink>
</NavItem>
<NavItem>
<NavLink
tag={Link}
d="navFetch"
className="text-dark inactive"
to="/fetch-data"
>
<img
src="/Images/NLUnactiveImg.png"
alt="Unactive Link Image"
height="45"
width="45"
/>
<img
src="/Images/NLActiveImg.png"
alt="Active Link Image"
height="45"
width="45"
hidden
/>
Fetch data
</NavLink>
</NavItem>
</ul>
</Collapse>
<div>
{' '}
<PlaySound child={this.state.child} />{' '}
</div>
</Navbar>
);
}
}
First of all remove you css (images) into a seperate css file. Make a class and put your css into that. Something like this
<NavLink tag={Link} d="navResume" className="text-dark inactive resumeImage" to="/resume">
Resume
</NavLink>;
in your css file
.resumeImage {
//declare your image styles here
}
Repeat above for all your Navlinks.
Now keep those styles which you only want to apply to the active link in a seperate class and apply that class to all the Navlinks like below
<NavLink
tag={Link}
d="navResume"
className="text-dark inactive resumeImage"
activeClassName="activestyleclass"
to="/resume"
>
Resume
</NavLink>;
You can check the current URL and change the image based on the url since active class should be depend on the url too.
You can use react hook useLocation to get current URL.
import { useLocation } from 'react-router-dom';
const Component= () => {
const [pathname, setPathname] = useState('/');
const location = useLocation();
useEffect(() => {
setPathname(location.pathname);
}, [location]);
return (
<nav className="navbar">
<NavLink to="/" className="navbar-item">
{pathname === '/' ? (
<img src="/images/navbar/home_active.png" alt="Home" />
) : (
<img src="/images/navbar/home.png" alt="Home" />
)}
</NavLink>
.....

Nav not collapsing when a NavItem is selected on mobile devices

I'm building a navbar that is expected to be responsive when it switches to mobile devices. In other words, collapse when mobile, then when the navitems are selected / clicked, it should route to the path and collapse all navitems to a toggle-style bar. However, below a snapshot of what I got and it's associated code:
CODE:
render() {
return (
!this.state.isAuthenticating &&
<div className="App">
<Navbar fluid collapseOnSelect>
<Navbar.Header>
<Navbar.Brand>
<LinkContainer to="/">
<a>
<img src={logo} alt="logo" height="70" width="75"/>
<p>hybriData</p>
</a>
</LinkContainer>
</Navbar.Brand>
<Navbar.Toggle />
</Navbar.Header>
<Navbar.Collapse>
<Nav pullRight>
{this.state.isAuthenticated
? <Fragment>
<LinkContainer to="/settings">
<NavItem>Settings</NavItem>
</LinkContainer>
<NavItem eventKey={1} onClick={this.handleLogout}>Logout</NavItem>
</Fragment>
: <Fragment>
<LinkContainer to="/About Us">
<NavItem eventKey={2}>About Us</NavItem>
</LinkContainer>
<LinkContainer to="/Contact">
<NavItem eventKey={3}>Contact</NavItem>
</LinkContainer>
<LinkContainer to="/works">
<NavItem eventKey={5}>Works</NavItem>
</LinkContainer>
<LinkContainer to="/signin">
<NavItem eventKey={6}>SignIn</NavItem>
</LinkContainer>
</Fragment>
}
</Nav>
</Navbar.Collapse>
</Navbar>
</div>
);
}
I also integrated some of this solution react-bootstrap how to collapse menu when item is selected using the expanded and onSelect props of the navbar and nav's activeKey and onSelect props to achieve desired functionality but to no fruition. How can I implement desired functionality of having all navitem's collapsed when any path(s) is navigated to , clicked / selected? Thank you
Here is a simplified working example. It's about the order of items. If you look at the bootstrap CSS, you see some styles like
.nav > li {
position: relative;
display: block;
}}
The > symbol is a selector that selects all immediate descendants or children (first 'wrap layer' only, not applied to second 'wrap layer'), namely if you have
<ul class="nav">
<div>
<li>something</li>
<li>something</li>
</div>
</ul>
the styles are not applied, while
<ul class="nav">
<li>something</li>
<li>something</li>
</ul>
works. In your case, try replacing the <Fragment> with <Nav> and remove the outer <Nav>.
Another part you may want to modify is the LinkContainer wrapping the NavItem part. Usually we have <li> (NavItem) wrapping <a> (Link) but not the other way round.
Although react-bootstrap makes the code easier to read, it abstracts the details and may be harder to get something working. If you have difficulty with react-bootstrap, I suggest you to stick with pure bootstrap elements. The codes are slightly longer but the appearance is the same. You can follow w3schools to use bootstrap styles.

Constructing HTML with IF ELSE

Hi I am trying to create HTML inside render where some of the portion is dependent on a condition which I am putting in IF ELSE. But if statement is been treated as plain text and not getting result as expected. Can someone tell me where am I wrong?
render(){
console.log('email'+this.state.email);
var html = <Navbar style={styles.menu} color="faded" light expand="md">
<NavbarBrand style={styles.image} href="/"><img src="../../images/op-logo.jpg"/></NavbarBrand>
<NavbarToggler onClick={this.toggle} />
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink href="/tournaments">Tournaments</NavLink>
</NavItem>
<NavItem>
<NavLink href="/players-ladder">Ladder</NavLink>
</NavItem>
if (this.state.email!='') {
('Welcome' + this.state.email+<NavItem><NavLink href="/logout">Logout</NavLink></NavItem>)
} else {
(<NavItem><NavLink href="/login">Login/Signup</NavLink></NavItem>)
}
</Nav>
</Collapse>
</Navbar>
return (
<div>
{html}
</div>);
}
Inside of jsx you can't use an if block because jsx gets parsed and transpiled to javascript and its syntax does not allow for it. But you can use the ternary operator in most cases to do conditional rendering:
{this.state.email ? (
<React.Fragment>
<p>{`Welcome ${this.state.email}`}</p>
<NavItem>
<NavLink href="/logout">Logout</NavLink>
</NavItem>
</React.Fragment>
) : (
<NavItem>
<NavLink href="/login">Login/Signup</NavLink>
</NavItem>
)}
Also note that you do not create html inside the render method. jsx gets fully transpiled to javascript. You can consider it to be an embedded template language with includes and partials in the form of react components with react being the rendering engine.

Hide collapse navbar after link click, react-redux, react-bootstrap

I'm beginner in react, so, need your help.
I used collapsible bootstrap navbar, have no ideas how to make it collapse after link click on mobile. Native bootsrap property collapseOnSelect not working, or i did something wrong.
const AppBar = () => (
<Navbar collapseOnSelect>
<Navbar.Header>
<Navbar.Brand>
<div className="logo-wrap">
<Link to="define">
<img height='50' src='./../assets/img/logo.png' className="logo"/>
</Link>
</div>
</Navbar.Brand>
<Navbar.Toggle />
</Navbar.Header>
<Navbar.Collapse>
<Nav>
<LinkContainer to="define" className="nav-link"><NavItem eventKey={1}>Home</NavItem></LinkContainer>
<LinkContainer to="about" className="nav-link"><NavItem eventKey={1}>About</NavItem></LinkContainer>
<LinkContainer to="features" className="nav-link"><NavItem eventKey={1}>Features</NavItem></LinkContainer>
<LinkContainer to="pricing" className="nav-link"><NavItem eventKey={1}>Pricing</NavItem></LinkContainer>
<LinkContainer to="areaMap" className="nav-link"><NavItem eventKey={1}>Area Map</NavItem></LinkContainer>
</Nav>
<Nav pullRight>
<LinkContainer to="login" className="nav-link"><NavItem eventKey={2}>Log In</NavItem></LinkContainer>
<LinkContainer to="registration"><NavItem eventKey={2}><Button className="sign-up">Sign Up</Button></NavItem></LinkContainer>
</Nav>
</Navbar.Collapse>
</Navbar>
);
export default AppBar;
const [expanded, setExpanded] = useState(false);
Second in the Navbar we add this prop:
<Navbar expanded={expanded}>
Third, we add an onClick event to the toggle handler that changes the menu visibility status:
<Navbar.Toggle onClick={() => setExpanded(expanded ? false : "expanded")} />
Fourth we add the prop
<Link to="/" onClick={() => setExpanded(false)}>Menu</Link>

Resources