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.
Related
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
Im trying to use this package to implement smooth scroll within a Navbar:
https://www.npmjs.com/package/react-scroll
Here's my navbar component:
Navbar.js
import React from "react";
import { Section1, Nav, NavLink, Bars, NavMenu } from "./NavbarElements";
import { Link, animateScroll as scroll } from "react-scroll";
const Navbar = () => {
return (
<>
<Section1>
<Nav>
<Bars />
<Link
activeClass="active"
to="section2"
spy={true}
smooth={true}
offset={-70}
duration={500}
>
Home
</Link>
<Link
activeClass="active"
to="section3"
spy={true}
smooth={true}
offset={-70}
duration={500}
>
Web
</Link>
<Link
activeClass="active"
to="section4"
spy={true}
smooth={true}
offset={-70}
duration={500}
>
Games
</Link>
<Link
activeClass="active"
to="section5"
spy={true}
smooth={true}
offset={-70}
duration={500}
>
About
</Link>
</Nav>
</Section1>
</>
);
};
export default Navbar;
and here's my App.js
App.js
import React from "react";
import "./App.css";
import Navbar from "./components/navbar";
import HomeSection from "./components/home-section";
import WebSection from "./components/web-section";
import GameSection from "./components/games-section";
import AboutSection from "./components/about-section";
function App() {
return (
<>
<Navbar />
<HomeSection id="section2" />
<WebSection id="section3" />
<GameSection id="section4" />
<AboutSection id="section5" />
</>
);
}
export default App;
What am I missing? I thought I ID'd everything correctly but maybe not? Sorry im a noob. Any glaring issues here I'm missing? Is there a better way to implement one page smooth scrolling with react?
https://imgur.com/PvRRMPL
The way react component works that anything you put in the angle bracket its gonna take it as a props here you are not setting up and id you are passing down the prop to your components
<HomeSection id="section2" /> //this is passing props to your homeSection Component
here is how you can fix it:
const HomeSection (props) =>{
return(
<div id={props.id}> //your parent div
</div>
)
or you can wrap it like that
<div id="id="section2"">
<HomeSection />
</div>
If anyone ever sees this and needs a solution, you need to wrap <Element> tags around the component like so:
import { Element } from "react-scroll";
const HomeSection = () => {
return (
<>
<Element id="section2" name="home">
<Section2>
/* CODE */
</Section2>
</Element>
</>
);
};
export default HomeSection;
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>
);
};
I am trying to show a custom PopUp component on the screen when a user clicks on the Info icon but nothing is rendering in the UI when clicked.
I'm not exactly certain where I'm going wrong if anyone could provide some guidance?
Here is my Card component with PopUp inside the return:
import React, { useState } from 'react';
import { Card } from 'react-bootstrap';
import InfoIcon from '#material-ui/icons/Info';
import PopUp from './PopUp';
const WelcomeCard = (props) => {
const [show, setShow] = useState(false);
const togglePop = () => {
setShow(true);
};
return (
<Card className='m-3 p-2 welcome-card rounded'>
<Card.Body>
<Card.Text className='mt-4'>{props.text}</Card.Text>
<Card.Title>{props.title}</Card.Title>
<button>{props.button}</button>
{show && <PopUp toggle={togglePop} />}
<InfoIcon className='info-icon' onClick={togglePop} />
</Card.Body>
</Card>
);
};
export default WelcomeCard;
And my actual PopUp component itself:
import React from 'react';
const PopUp = (props) => {
const handleClick = () => {
props.toggle();
};
return (
<div className='modal'>
<div className='modal_content'>
<span className='close' onClick={handleClick}>
×
</span>
<form>
<h3>Register!</h3>
<label>
Name:
<input type='text' name='name' />
</label>
<br />
<input type='submit' />
</form>
</div>
</div>
);
};
export default PopUp;
Would really appreciate some help on this one to understand it better, thanks in advance!
I am working on an application that changes the order of a product grid by rearranging tiles. (It is like Packery). I have a renderData function that populates the layout grid with data from a file input. That is working fine. The part that I am struggling with, is how then do I save that "layout" - by that I mean the order of the items - how do I save that to state?
When the user re-sorts the times in the UI, I want that layout array to change to reflect the new order.
It seems so simple, but I just haven't seen yet how to do it.
import React, { Component } from 'react'
import Papa from 'papaparse'
import GridLayout from 'react-grid-layout'
import {
Jumbotron,
Container,
Collapse,
Navbar,
NavbarToggler,
NavbarBrand,
Nav,
NavItem,
NavLink,
UncontrolledDropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
Button,
Input,
} from 'reactstrap'
import '../node_modules/react-grid-layout/css/styles.css'
import '../node_modules/react-resizable/css/styles.css'
import './App.css'
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [], // on load
isOpen: false,
};
this.toggle = this.toggle.bind(this);
this.handleChange = this.handleChange.bind(this);
this.updateData = this.updateData.bind(this)
this.renderData = this.renderData.bind(this)
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
handleChange(event) {
event.preventDefault()
const inventory = event.target.files[0]
Papa.parse(inventory, {
header: true,
complete: this.updateData
})
} // END
updateData(results) {
const data = results.data
this.setState({data}) // {data:data}
}
renderData() {
return this.state.data.map((item,index) => (
<div className="react-grid-item grid-item" key={item.sku} data-grid={{x: index % 3, y: Math.floor(index / 3), w: 1, h: 1}}>
<div> {item.name} </div>
<div> {item.gridorder} </div>
<div> {item.designer} </div>
<img src={item.image} alt="product" />
<div> {item.sku} </div>
<div> {index} </div>
</div>
))
}
// QUESTION: How do I save this layout to state each time it rerenders?
// NOTE: on click of export button, I want to pass that reordered layout held in state to handleClick and parse it back to CSV
// handleClick(event) {
// Papa.unparse({
// })
// }
render() {
return (
<div>
<Navbar color="dark" dark expand="md">
<NavbarBrand href="/">GO App - grid order tool</NavbarBrand>
<NavbarToggler onClick={this.toggle} />
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink href="/components/">Components</NavLink>
</NavItem>
<NavItem>
<NavLink href="https://github.com/reactstrap/reactstrap">GitHub</NavLink>
</NavItem>
<UncontrolledDropdown nav inNavbar>
<DropdownToggle nav caret>
Options
</DropdownToggle>
<DropdownMenu right>
<DropdownItem>
Option 1
</DropdownItem>
<DropdownItem>
Option 2
</DropdownItem>
<DropdownItem divider />
<DropdownItem>
Reset
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
</Nav>
</Collapse>
</Navbar>
<Jumbotron >
<Container>
<h4> Import CSV </h4>
<Input type="file" onChange={this.handleChange} />
</Container>
</Jumbotron>
<Container className="album ">
<div className="note" > BUG: Drag tiles from text, not image </div>
<div className="note" > BUG: Drag order will be changed </div>
<GridLayout compactType="horizontal" useCSSTransforms={true} cols={3} margin={[120, 20]} rowHeight={300} className="react-grid-layout grid" width={1200} >
{this.renderData()}
</GridLayout>
<Navbar color="light" light expand="md">
<Collapse isOpen={this.state.isOpen} navbar>
<Nav className="ml-auto" navbar>
<NavItem>
<div className="note" > NOTE: The export function is under construction </div>
<Button onClick={this.handleClick} color="secondary" size="sm">Export CSV</Button>
</NavItem>
</Nav>
</Collapse>
</Navbar>
</Container>
</div> // END
);
}
} // END
export default App
You can move the state one component above and make the grid display of itens a functional component that only receives an array and display the grid.
With that said, to sort the list, on the parent component, you call the
this.setState({data: this.state.data.sort(...)})
and pass this to the child that expects an array to display the grid. So the render method on the parent component should be:
render () {
const { data } = this.state;
return (
<ChildComponent itensList={data} />
);
}