How to change react icons while clicking it? - javascript

I have some icons from react-icons that I want to change from outline to filled whenever I click it but instead of changing itself, it changes all the icons from outline to filled.
Here is my code
function Header() {
const [isActive, setIsActive] = useState(false);
return (
....
<div className="flex items-center space-x-6">
<div className="cursor-pointer select-none">
{isActive? <AiOutlineHome onClick={()=>{
setIsActive(!isActive)}}/>:
<AiFillHome onClick={()=>{
setIsActive(!isActive)}} />
}
</div>
<div className="cursor-pointer select-none">
{isActive?<MdOutlineAddBox onClick={()=>{
setIsActive(!isActive)}}/>:
<MdAddBox onClick={()=>{
setIsActive(!isActive)}} />}
</div>
....
)}
I know it's because they are sharing the same isActive state, but I don't know exactly how to fix it. Can someone please help me with this?
Edit:
function HeaderIcon({ Icon, ActiveIcon }) {
const [isActive, setIsActive] = useState(false);
return (
<div>{isActive ? <Icon /> : <ActiveIcon />}</div>
);
}
export default HeaderIcon;
I put this component in a new file but how can I pass the onClick to it?

You need to use two different state
function Header() {
const [isActive, setIsActive] = useState(false);
const [isActive2, setIsActive2] = useState(false);
return (
....
<div className="flex items-center space-x-6">
<div className="cursor-pointer select-none">
{isActive? <AiOutlineHome onClick={()=>{
setIsActive(!isActive)}}/>:
<AiFillHome onClick={()=>{
setIsActive(!isActive)}} />
}
</div>
<div className="cursor-pointer select-none">
{isActive2?<MdOutlineAddBox onClick={()=>{
setIsActive2(!isActive2)}}/>:
<MdAddBox onClick={()=>{
setIsActive2(!isActive2)}} />}
</div>
....
)}
I hope this will do magic

The answer for this is:
import React, { useState } from "react";
function HeaderIcon({ inactiveIcon, activeIcon }) {
const [isActive, setIsActive] = useState(false);
return (
<div onClick={() => setIsActive(!isActive)}>
{isActive ? activeIcon : inactiveIcon}
</div>
);
}
export default HeaderIcon;
Then pass in the icon you want.

Related

How do I show data on one card when hovering and not on all?

Okay there is definitely a quick solution for this I just can't figure out.
Just a description of what I am trying to do:
Whenever I hover over a certain card, I would like to see the description of that item and only that item. But instead what's obviously happening, as you can see from my code, is every single cards description is showing.
I rewrote a simpler version of the code by taking out any unnecessary pieces. Everything is imported correctly, styling and classNames were removed as well.
export function Items() {
const [items, setItems] = useState([])
const [isHovering, setIsHovering] = useState(false)
useEffect(() => {
setItems(Data)
}, [])
function handleMouseOver() {
setIsHovering(true)
}
function handleMouseOut() {
setIsHovering(false)
}
return(
<div>
{items.map(item => {
return(
<Card onMouseOver={handleMouseOver} onMouseOut={handleMouseOut} key={item.id}>
{isHovering ?
<Card.Body>
<p>{item.item_description}</p>
</Card.Body>
:
<Card.Body>
</Card.Body>
}
<Card.Footer>
</Card.Footer>
</Card>
)
})}
</div>
)
}
As far as I can see you don't need to put this logic into parent component, and also it makes everything more complex, since it's hard to manage hovering. I would create new chlid component and manage this state out there internally.
export function Item({item}) {
const [isHovering, setIsHovering] = useState(false);
useEffect(() => {
setItems(Data);
}, []);
function handleMouseOver() {
setIsHovering(true);
}
function handleMouseOut() {
setIsHovering(false);
}
return (
<Card onMouseOver={handleMouseOver} onMouseOut={handleMouseOut}>
{isHovering ? (
<Card.Body>
<p>{item.item_description}</p>
</Card.Body>
) : (
<Card.Body></Card.Body>
)}
<Card.Footer></Card.Footer>
</Card>
);
}
export function Items() {
const [items, setItems] = useState([]);
return (
<div>
{items.map(item => (
<Item key={item.id} item={item} />
))}
</div>
);
}
Your "isHovering" state should also be an array, where you store the hover state for every card. Then on hover set "isHovering" to true only for the right card.

React- pass {selected, setSelected} as a object props to component?

I'm learning how to do dropdown menu from a tutorial.
There are some parts that I don't know..
why pass {selected, setSelected} as a object props to Dropdown component instead of using selected, setSletected directly? I've tried and it throws an error.
at this part
{options.map((option) => (
<div
onClick={(e) => {
setSelected(option);
}}
>
the tutorial initially
used onClick={(e) => {setSelected(e.target.textContent);}}
why have to change e.target.textContent into option?
how do program know which item is selected exactly by option without using e.target.textContent?
function App() {
const [selected, setSelected] = React.useState("Choose One");
return (
<div>
{/* custom dropdown menu */}
<Dropdown selected={selected} setSelected={setSelected} />
{selected}
</div>
);
}
function Dropdown({ selected, setSelected }) {
const [isActive, setIsActive] = React.useState(false);
const options = ["React", "Vue", "Angular"];
return (
<div onClick={(e) => setIsActive(!isActive)}>
{isActive && (
<div>
{options.map((option) => (
<div
onClick={(e) => {
setSelected(option);
}}
></div>
))}
</div>
)}
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

unable to access custom component property from parent component

I have created one custom component, alternative of Select component, on click shows ul and on click hide ul.
when I click I can set value to the state inside function, but i want to access the value in parent component.
so my component is
const [showMenu, setShowMenu] = useState(false);
const [value, setValue] = useState();
return (
<>
<button
className='btn'
onClick={() =>
showMenu ? setShowMenu(false) : setShowMenu(true)
}>
{props.name}
</button>
<ul className={showMenu ? "" : "hide"}>
{props.listsa.map((element) => {
return (
<li
key={element.key}
value={element.value}
onClick={(e) => {
setValue(e.target.value);
}}>
{element.label}
</li>
);
})}
</ul>
</>
I want to access value mentioned above functional component in parent component, which is my app.js
as shown below, this is return method of parent component.
<div className='App'>
{/* <Main /> */}
<OptionsComponent name='ABC Menu' listsa={abc} />
{/* here I want to use that value to perfom operations/ also on change it should show changed value */}
</div>
I tried using localStorage.setItem("value":value) it works but that will use browser memory so I am looking for alternative way.
I tried exporting variable, it shows undefined, also I tried making varibale global, it works but doesnt reflect change.
any help will be appreciated
You just need to bring the state up and pass it down, instead:
const [value, setValue] = useState();
return (
<div className='App'>
{/* <Main /> */}
<OptionsComponent name='ABC Menu' listsa={abc} value={value} setValue={setValue}/>
</div>
And
const [showMenu, setShowMenu] = useState(false);
return (
<>
<button
className='btn'
onClick={() =>
showMenu ? setShowMenu(false) : setShowMenu(true)
}>
{props.name}
</button>
<ul className={showMenu ? "" : "hide"}>
{props.listsa.map((element) => {
return (
<li
key={element.key}
value={element.value}
onClick={(e) => {
props.setValue(e.target.value);
}}>
{element.label}
</li>
);
})}
</ul>
</>
);

How to toggle Sidebar Component in Header with a Burger Menu using Hooks in React

I am very new in React and maybe someone could help me.
I want to toggle my Sidebar in my Header Component with Hooks.
This is my Code:
Sidebar.js
...imported things
...styles
export const SideBar = () => {
const history = useHistory();
return (
<StyledSideBar>
<Tooltip title="Dashboard" placement="right" arrow >
<StyledButton onClick={() => history.push('/dashboard')}>
<FontAwesomeIcon icon={faTachometerAltFast} />
</StyledButton>
</Tooltip >
<Tooltip title="Chat" placement="right" arrow>
<StyledButton onClick={() => history.push('/chat')}>
<FontAwesomeIcon icon={faCommentsAlt} />
</StyledButton>
</Tooltip>
<Tooltip title="Calendar" placement="right" arrow>
<StyledButton onClick={() => history.push('/calendar')}>
<FontAwesomeIcon icon={faCalendarAlt} />
</StyledButton>
</Tooltip>
</StyledSideBar>
);
}
export default SideBar;
Header.js
...imported things
...styles
import SideBar from '../sidebar';
export const MainHeader = () => {
const [show, setShow] = React.useState(false);
const toggle = () => setShow(!show);
return (
<AppBar elevation={2} position="sticky" color="inherit" >
<FlexToolbar variant="regular">
<StyledMenuIcon open={show} onClick={toggle.{SideBar}>
<FontAwesomeIcon icon={faBars} />
</StyledMenuIcon>
<Logo src="/assets/images/logo.svg" alt="Vetera Sky" />
<BreakpointLogo src="/assets/images/get-started-icon.svg" alt="Vetera Sky" />
<Spacer />
<LogoutButton onClick={onLogout}>
<FontAwesomeIcon icon={faPowerOff} />
<Typography variant="label" color={actionSecondary}>Logout</Typography>
</LogoutButton>
<BreakpointLogoutButton onClick={onLogout}>
<FontAwesomeIcon icon={faPowerOff} />
</BreakpointLogoutButton>
</FlexToolbar>
</AppBar>
)};
export default MainHeader;
I know this is wrong, but i could not find anything in the Web or in here.
If the StyledMenuIcon is clicked once, the Sidebar should open on the left and if clicked again it should close.
Hope someone can help me soon :)
You should move your state higher up in the tree where both MainHeader and SideBar components can use it:
function App() {
const [showSidebar, setShowSidebar] = useState(false);
const onToggleSidebar = () => {
setShowSidebar(!showSidebar);
};
return (
<MainHeader onToggleSidebar={onToggleSidebar} />
<SideBar open={showSidebar}
);
}
If the components aren't available on the same level in the tree, you could use React's context api to use this logic from different places down the tree.
Or if you're already using something like redux or another state management system you could move your app state there.

React Material UI + React Router >>>> I cannot use Redirect inside a onClick function in a button

I am trying to trigger the Redirect React Dom
that is my button component in the handleMenuItemClick() function. But nothing happens.
I have tried a bunch of stuff but but still no success.
How can I make the both work together? My best try was to make a function that return the Redirect component as I saw in one post around, but still no success.
My Code:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { Grid, Button, ButtonGroup, ArrowDropDownIcon, ClickAwayListener, Grow, Paper, Popper, MenuItem, MenuList, Link } from '#material-ui/core/Grid';
const SplitButton = (props) => {
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const [selectedIndex, setSelectedIndex] = React.useState(1);
const myGroups = props.myGroups
const handleMenuItemClick = (event, index) => {
setSelectedIndex(index);
setOpen(false);
return <Redirect to={`/groups/${index}`} />
};
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
return (
<>
<ButtonGroup variant="contained" color="primary" ref={anchorRef} aria-label="split button">
<Button onClick={null}>My Groups</Button>
<Button
color="primary"
size="small"
aria-controls={open ? 'split-button-menu' : undefined}
aria-expanded={open ? 'true' : undefined}
aria-label="select merge strategy"
aria-haspopup="menu"
onClick={handleToggle}
>
<ArrowDropDownIcon />
</Button>
</ButtonGroup>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom',
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList id="split-button-menu">
{ myGroups.map((group) => (
<MenuItem
key={group.id}
onClick={(event) => handleMenuItemClick(event, group.id)}
>
{group.title}
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</>
);
}
export default SplitButton
You can redirect user via 2 methods: useHistory or <Redirect />
useHistory hook
If you want to redirect the user directly on click, you can treat the code imperatively and tell React what to do:
const history = useHistory();
const handleMenuItemClick = (event, index) => {
setSelectedIndex(index);
setOpen(false);
history.push(`/groups/${index}`)
};
More info https://reactrouter.com/web/api/Hooks/usehistory
Redirect component
Or if you feel more comfortable using React's default declarative model, you can say what's changed and allow your code to react to this change:
const [redirectUrl, setRedirectUrl] = useState('')
const handleMenuItemClick = (event, index) => {
setSelectedIndex(index);
setOpen(false);
setRedirectUrl(`/groups/${index}`)
};
if (redirectUrl) {
return <Redirect to={redirectUrl} />
}
return (
<>
<ButtonGroup variant="contained" color="primary" ref={anchorRef} aria-label="split button">
<Button onClick={null}>My Groups</Button>
<Button
...
More info https://reactrouter.com/web/api/Redirect

Categories