toggling class dynamically in react? - javascript

I am working on a React application that has a header component with two buttons:
import React, { useRef } from 'react';
import { Link } from 'react-router-dom';
const Header = () => {
return (
<header className='header'>
<h2 className='resume-title'>
Muhammad <br />
Sohaib Furqan
</h2>
<button className='btn'>
<Link to='/'>Home</Link>
</button>
<button className='btn'>
<Link to='/projects'>Projects</Link>
</button>
</header>
);
};
I want to make it so that the button that is clicked gets the 'active' class while the other buttons the 'active' class is removed. In vanillaJS, I would use 'querySelectorAll' to get all buttons and then map through the nodeList, toggling as appropriate. But not sure how I would do that in React. I'm inclined towards useRef but how can I set ref to point to the button that was clicked?
Hope I've managed to make myself clear.
TIA,
Sohaib

See NavLink.
You can use it like
<NavLink className="btn" to='/'>Home</Link>
NavLink will get .active class when path matches. So you can add styles to the active class.
You can also customize the className using
<NavLink to="/" activeClassName="some-custom-class">
Home
</NavLink>

<Link> no longer has the activeClassName or activeStyle properties. In react-router v4 you have to use <NavLink> if you want to do conditional styling:
import React, { useRef } from 'react';
import { NavLink } from 'react-router-dom';
const Header = () => {
return (
<header className='header'>
<h2 className='resume-title'>
Muhammad <br />
Sohaib Furqan
</h2>
<NavLink to='/' className="btn" activeClassName="active">Home</Link>
<NavLink to='/projects' className="btn" activeClassName="active">Projects</Link>
</header>
);
};
and in your style.css
.active { //do-whatever }

import React, { useState } from 'react';
import { Link } from 'react-router-dom';
const Header = () => {
const [active,setActive] = useState("Home")
const handleActive = (activeTab) => {
setActive(activeTab)
}
return (
<header className='header'>
<h2 className='resume-title'>
Muhammad <br />
Sohaib Furqan
</h2>
<button className={active === "Home" ? 'btn active' : 'btn' } onClick={() => handleActive("Home")} >
<Link to='/'>Home</Link>
</button>
<button className={active === "Projects" ? 'btn active' : 'btn' } onClick={() => handleActive("Projects")} >
<Link to='/projects'>Projects</Link>
</button>
</header>
);
};

Related

Getting Blank Screen while running npm start for react project

I was trying to make a profile portfolio website using react in which i made a NavBar.js for Navigation bar which i have imported in my App.js file.
But now when i was trying to run the code instead of showing the navigation bar it was showing the blank screen
NavBar.js
import { Navbar, Nav, Container } from "react-bootstrap";
import logo from '/Users/rijuljain/Documents/portfolio/portfolio-web/src/assets/img/logo.svg';
import navIcon1 from '/Users/rijuljain/Documents/portfolio/portfolio-web/src/assets/img/nav-icon1.svg';
import navIcon2 from '/Users/rijuljain/Documents/portfolio/portfolio-web/src/assets/img/nav-icon2.svg';
import navIcon3 from '/Users/rijuljain/Documents/portfolio/portfolio-web/src/assets/img/nav-icon3.svg';
import { HashLink } from 'react-router-hash-link';
import {
BrowserRouter as Router
} from "react-router-dom";
export const NavBar = () => {
const [activeLink, setActiveLink] = useState('home');
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const onScroll = () => {
if (window.scrollY > 50) {
setScrolled(true);
} else {
setScrolled(false);
}
}
window.addEventListener("scroll", onScroll);
return () => window.removeEventListener("scroll", onScroll);
}, [])
const onUpdateActiveLink = (value) => {
setActiveLink(value);
}
return (
<Router>
<Navbar expand="md" className={scrolled ? "scrolled" : ""}>
<Container>
<Navbar.Brand href="/">
<img src={logo} alt="Logo" />
</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav">
<span className="navbar-toggler-icon"></span>
</Navbar.Toggle>
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="ms-auto">
<Nav.Link href="#home" className={activeLink === 'home' ? 'active navbar-link' : 'navbar-link'} onClick={() => onUpdateActiveLink('home')}>Home</Nav.Link>
<Nav.Link href="#skills" className={activeLink === 'skills' ? 'active navbar-link' : 'navbar-link'} onClick={() => onUpdateActiveLink('skills')}>Skills</Nav.Link>
<Nav.Link href="#projects" className={activeLink === 'projects' ? 'active navbar-link' : 'navbar-link'} onClick={() => onUpdateActiveLink('projects')}>Projects</Nav.Link>
</Nav>
<span className="navbar-text">
<div className="social-icon">
<img src={navIcon1} alt="" />
<img src={navIcon2} alt="" />
<img src={navIcon3} alt="" />
</div>
<HashLink to='#connect'>
<button className="vvd"><span>Let’s Connect</span></button>
</HashLink>
</span>
</Navbar.Collapse>
</Container>
</Navbar>
</Router>
)
}
App.js
import 'bootstrap/dist/css/bootstrap.min.css';
import { NavBar } from "/Users/rijuljain/Documents/portfolio/portfolio-web/src/components/NavBar.js";
function App() {
return (
<div className="App">
<NavBar />
</div>
);
}
export default App;
this is the blank screen i'm getting:
plz tell what changes should i do to make it write. thank you
I'm not getting any error in my console, there it is compiling perfectly but it is not showing any output in the localhost screen
console output
enter image description here
These are the images of browser Consoleenter image description here
enter image description hereenter image description here

How to import parameters from one React component to another

Please apologize my lack of knowledge but I'm new to React and JavaScript.
I'm building a Website where I have a Sidebar and a Navbar on top of the page. The Sidebar is activated / deactivated via an hamburger menu which is located in the Navbar-component. It is activated via CSS-classes: <nav className={isActive ? 'nav-menu active' : 'nav-menu'}>
My Problem now is, that I dont know how to transfer the variables toggleButton and isActive from the Navbar.jsx where they are declared to the Sidebar.jsx where I need them to activate my Sidebar.
Do I need to import the js files? Is it possible to export isActive and toggleButton seperatly from the JSX-Code?
Thanks for your help! :)
This is my Code:
Navbar-component
import React from "react";
import Navbar from "react-bootstrap/Navbar";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import Nav from "react-bootstrap/Nav";
import FormControl from "react-bootstrap/Form";
import Dropdown from "react-bootstrap/Dropdown";
import './Navbar.css';
const NavbarTop = () => {
const [isActive, setIsActive] = useState(false)
const toggleButton = useCallback(
() => setIsActive(prevState => !prevState),
[],
);
return (
<>
<Navbar className="background-color" variant="light">
<Navbar.Brand href="#home">
<img
src="https://pbs.twimg.com/profile_images/603568605796634624/Nq0nXZZA_400x400.jpg"
width="30"
height="30"
className="d-inline-block align-top"
alt="React Bootstrap logo"
/>
</Navbar.Brand>
<Dropdown>
<Dropdown.Toggle Classname="color" rvariant="success" id="dropdown-basic">
Kategorien
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item href="#/action-1">Bücher</Dropdown.Item>
<Dropdown.Item href="#/action-2">Veranstaltungen</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item href="#/action-3">Etwas Posten</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
<Form inline>
<FormControl type="text" placeholder="Search" className="mr-sm-2" />
<Button variant="outline-primary">Search</Button>
</Form>
<Link to='#' className='menu-bars'>
<HamburgerSpring className="Hamburger"
buttonColor="transparent"
barColor="#007466"
buttonWidth={35}
{...{ isActive, toggleButton }}
/>
</Link>
</Animate>
</Navbar>
</>
);
};
export default NavbarTop;
Sidebar-component:
import React, { useState, useCallback } from 'react';
import { Link } from 'react-router-dom';
import { SidebarData } from './SidebarData';
import { IconContext } from 'react-icons';
import {Animate} from 'react-rebound';
import { HamburgerSpring } from 'react-animated-burgers';
import './Sidebar.css';
function Sidebar(isActive, toggleButton) {
return (
<>
<IconContext.Provider value={{ color: 'white' }}>
<nav className={isActive ? 'nav-menu active' : 'nav-menu'}>
<div className='nav-menu-items'>
<ul onClick={toggleButton}>
{SidebarData.map((item, index) => {
return (
<li key={index} className={item.cName}>
<Link to={item.path}>
{item.icon}
<span>{item.title}</span>
</Link>
</li>
);
})}
</ul>
</div>
</nav>
</IconContext.Provider>
</>
);
}
export default Sidebar;
One possible approach is to move the state one level up.
const ParentComponent = () => {
const [isActive, setIsActive] = useState(false)
const toggleButton = useCallback(
() => setIsActive(prevState => !prevState),
[],
);
.....
.....
{/* You can use like this */}
<SideBar isActive={isActive} toggleButton={toggleButton} />
<NavBar isActive={isActive} toggleButton={toggleButton} />
}
Alternatively, you can use the context API to store to hold the state and access it anywhere within the app. In your case, I think the first option is a better idea given it's simple nature.
This is where you'd lift state up, outside of those into a container of sorts.
function Container() {
const [toggleIsActive, setToggleIsActive] = useState(false);
return (
<Navbar ... toggleIsActive={toggleIsActive} setToggleIsActive={setToggleIsActive} />
<Sidebar ... toggleIsActive={toggleIsActive} setToggleIsActive={setToggleIsActive} />
)
}
Essentially you track that from higher up in the tree while providing the values/methods for changing to the children components.

React way to open a NavBar onClick on a button

I trying to find a way to open the navbar of ReactJS app when i'm clicking on my "MENU" button.
At the beginning my nav component have a width of 0px (with overflow : hidden). When i'm clicking on the button my nav should have a width of 400px. I'm a beginner with React.
I have two React Components :
Topbar
export default function Topbar() {
return (
<div className="topbar__container">
<div className='topbar__menuButton'>
<Link className="topbar__link">MENU</Link>
</div>
<div className="topbar__title">
<Link to="/" className="topbar__link">EDGAR</Link>
</div>
</div>
)
}
Nav
const Nav = () => {
return (
<div className="navbar__container">
<Query query={CATEGORIES_QUERY} id={null}>
{({ data: { categories } }) => {
return (
<nav className="nav">
<ul>
{categories.map((category, i) => {
return (
<li key={category.id}>
<Link to={`/category/${category.id}`} className="nav__link">
{category.name}
</Link>
</li>
)
})}
</ul>
</nav>
)
}}
</Query>
</div>
)
}
export default Nav
To achieve something like that you have to set this logic in the common parent of both component (here App for the example).
App will manage a state to determine if the Nav is open or not. The state is called isMenuOpen and can be changed using the setIsMenuOpen() function. We will give to the children Nav the state isMenuOpen and to the children TopBar a callback from the function setIsMenuOpen():
App.jsx
import React from "react";
import TopBar from "./TopBar";
import Nav from "./Nav";
export default function App() {
const [isMenuOpen, setIsMenuOpen] = React.useState(false);
return (
<div className="App">
<TopBar setMenuStatus={setIsMenuOpen} />
<Nav isOpen={isMenuOpen} />
</div>
);
}
Then the TopBar have to set the value of isMenuOpen to true using the function setIsMenuOpen() from the props.
TopBar.jsx
import React from "react";
export default function Topbar({ setMenuStatus }) {
return (
<div className="topbar__container">
<div className="topbar__menuButton">
<button
type="button"
onClick={() => {
setMenuStatus(true);
}}
>
Menu
</button>
</div>
</div>
);
}
Then the component Nav will set a specific class (here .open) if isOpen coming from props is true.
Nav.jsx
import React from "react";
import "./styles.css";
export default function Nav({ isOpen }) {
return (
<div id="nav" className={isOpen ? "open" : ""}>
Menu
</div>
);
}
styles.css
#nav {
display: none;
}
#nav.open {
height: 400px;
display: inline-block;
}
You can try this example in this codesandbox.
import React, {useState} from "react";
import "./styles.css";
export default function App() {
const [toggle, setToggle]= React.useState(false)
const [width, setWidth]= React.useState('')
const showMenu = () => {
setToggle(!toggle)
if(toggle === true) {
setWidth('50px')
}else {
setWidth('500px')
}
}
return (
<div className="App">
<button onClick={showMenu}>Menu</button>
<div style={{width, border:'1px solid red'}}>
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
</div>
</div>
);
}
reproducing link: https://codesandbox.io/s/billowing-flower-rxdk3?file=/src/App.js:0-592

bulma menu toggle in gatsbyjs not working

GatsbyJS beginner here, trying to get the Bulma responsive menu toggle to apply the "is-active" class to the menu (gatsby v2 with gatsby starter netlify cms). all code here: https://github.com/pddew/gatsby-starter-netlify-cms
Currently the toggle button and script tags appear but the button doesn't respond.
There is a working version of this in the gatsby starter business- when I inspect and compare my site with this, I can't spot the error, only that there is no event listener on toggle button, when it seems there should be.
When I inspect the site, the toggle.js script is being called and put in before the closing body tag, and the viewed.
I have tried building and deploying with no luck, clearing caches and swapping the scripts for bulma's suggested code.
Here is the relevant code.
Any help with this greatly appreciated; I'm a bit stuck!
in Layout.js:
import React from 'react' import Helmet from 'react-helmet'
import Navbar from '../components/Navbar' import Footer from '../components/Footer' import './all.sass'
const TemplateWrapper = ({ children }) => ( <div>
<Helmet title="Immediate Start Jobs" />
<Navbar />
<div>{children}</div>
<Footer /> </div> )
export default TemplateWrapper
in Navbar:
<button className="button navbar-burger" data-target="navMenu">
<span />
<span />
<span />
</button>
</div>
<div className="navbar-menu" id="navMenu">
<div className="navbar-start">
<Link className="navbar-item" to="/about">
About
</Link>
<Link className="navbar-item" to="/products">
Products
</Link>
<Link className="navbar-item" to="/blog">
Blog
</Link>
</div>
in html.js
import React from "react"
import PropTypes from "prop-types"
export default class HTML extends React.Component {
render() {
return (
<html {...this.props.htmlAttributes}>
<head>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
{this.props.headComponents}
</head>
<body {...this.props.bodyAttributes}>
{this.props.preBodyComponents}
<div
key={`body`}
id="___gatsby"
dangerouslySetInnerHTML={{ __html: this.props.body }}
/>
{this.props.postBodyComponents}
<script src={__PATH_PREFIX__ + '/js/toggle.js'} />
</body>
</html>
)
}
}
HTML.propTypes = {
htmlAttributes: PropTypes.object,
headComponents: PropTypes.array,
bodyAttributes: PropTypes.object,
preBodyComponents: PropTypes.array,
body: PropTypes.string,
postBodyComponents: PropTypes.array,
}
And my toggle.js, stored in static/js/
document.addEventListener('DOMContentLoaded', function () {
// Get all "navbar-burger" elements
var $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0)
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
// Add a click event on each of them
$navbarBurgers.forEach(function ($el) {
$el.addEventListener('click', function () {
// Get the target from the "data-target" attribute
var target = $el.dataset.target
var $target = document.getElementById(target)
// Toggle the className on both the "navbar-burger" and the "navbar-menu"
$el.classList.toggle('is-active')
$target.classList.toggle('is-active')
})
})
}
})
I'm new to Gatsby myself, but I had to find a way to get my navbar to function. My solution is pretty quick and dirty, but it works. If your building a website with a lot of components that change state, I would suggest using redux and a central store instead. My solution was just having a navbar that handled its own state.
import React, { Component } from 'react'
import Link from 'gatsby-link'
class Navbar extends Component {
state = {
//This sets the state of Bulma elements
navbarIsActive: "navbar-item has-dropdown"
}
//This opens the navbar dropdown
navbarOpenDropdown = () => {
this.setState({
navbarIsActive: "navbar-item has-dropdown is-active"
})
}
//This closes the navbar dropdown
navbarCloseDropdown = () => {
this.setState({
navbarIsActive: "navbar-item has-dropdown"
})
}
render() {
return(
<div>
<nav class="navbar is-transparent" role="navigation" aria-label="dropdown navigation">
<a class="navbar-item">
<h1>Title!</h1>
</a>
<div
class={this.state.navbarIsActive}
onMouseEnter={this.navbarOpenDropdown}
onMouseLeave={this.navbarCloseDropdown}
>
<a class="navbar-link">
Docs
</a>
<div class="navbar-dropdown is-boxed">
<Link to="/">Home</Link>
<Link to="/about">About Us</Link>
<Link to="/blog">Blog</Link>
<hr class="navbar-divider"/>
<div class="navbar-item">
Version 0.7.2
</div>
</div>
</div>
</nav>
<section class="hero">
<div class="hero-body">
<p class="title">
Documentation
</p>
<p class="subtitle">
Everything you need to <strong>create a website</strong> with Bulma
</p>
</div>
</section>
</div>
)
}
}
export default Navbar;
That's just my two pennies' worth: https://nhpcr.codesandbox.io/
src/Navbar.js
import React from 'react';
import PropTypes from 'prop-types';
const NavbarItem = props => (
<a className="navbar-item is-capitalized" href={`#${props.page}`}>
{props.page}
</a>
);
const NavbarBurger = props => (
<button
onClick={props.toggleMenu}
className={`button navbar-burger ${props.active ? 'is-active' : ''}`}
>
<span />
<span />
<span />
</button>
);
export default class Navbar extends React.Component {
state = {
activeMenu: false,
};
toggleMenu = () => {
this.setState({
activeMenu: !this.state.activeMenu,
});
};
render() {
let { pages = [], color } = this.props;
let navbarItems = pages.map(page => <NavbarItem page={page} key={page} />);
return (
<nav className={`navbar is-fixed-top is-${color}`}>
<div className="navbar-brand">
<NavbarItem page="logo" />
<NavbarBurger
active={this.state.activeMenu}
toggleMenu={this.toggleMenu}
/>
</div>
<div
className={`navbar-menu ${this.state.activeMenu ? 'is-active' : ''}`}
>
<div className="navbar-start">{navbarItems}</div>
</div>
</nav>
);
}
}
Navbar.propTypes = {
pages: PropTypes.array.isRequired,
color: PropTypes.string,
};
src/index.js
import React from 'react';
import { render } from 'react-dom';
import Navbar from './Navbar';
import 'bulma/css/bulma.css';
const styles = {
fontFamily: 'sans-serif',
textAlign: 'center',
};
const pages = ['about', 'contact', 'sitemap'];
const App = () => (
<div style={styles}>
<Navbar pages={pages} />
</div>
);
render(<App />, document.getElementById('root'));

Toggle classes (navbar burger menu [show, hide]) | works in 'develop' but not in 'build'

In the Navbar.js component I want to be able to set state to true or false of the is-active css class, so that when the user presses the burger menu button, the menu shows or hides.
The code below works in the gatsby develop but not in the gatsby build.
There are no errors in 'build'.
Question: Why the code below does not work in gatsby build?
import React from 'react';
import Link from 'gatsby-link';
import logo from '../img/logo.svg';
class Navbar extends React.Component {
state = { showMenu: false }
toggleMenu = () => {
this.setState({
showMenu: !this.state.showMenu
})
}
render() {
const menuActive = this.state.showMenu ? 'is-active' : '';
const burgerActive = this.state.showMenu ? 'is-active' : '';
return (
<nav className="navbar">
<div className="navbar-brand">
<Link className="navbar-item" to="/">
<img src={logo} style={{ width: '88px' }} itemprop="image" alt="" />
</Link>
<div className={`navbar-burger burger ${burgerActive}`} onClick={this.toggleMenu}>
<span></span>
<span></span>
<span></span>
</div>
</div>
<div className={`navbar-menu ${menuActive}`} >
<div className="navbar-start">
<Link className="navbar-link" to="/" onClick={this.toggleMenu}>
Home
</Link>
<Link className="navbar-link" to="/services" onClick={this.toggleMenu}>
Services
</Link>
<Link className="navbar-link" to="/contact" onClick={this.toggleMenu}>
Contact
</Link>
</div>
</div>
</nav>)
}
};
export default Navbar;

Categories

Resources