add background color onClick in react - reactjs

so i have this flexbox:
[![flexbox][1]][1]
what i need is this:
when i press on any the divs on the left from overview to the bottom i need it to be colored in white the background just like in the image, i'm new to react and i'm trying to go through this project can anyone help me with this i'm stuck.
code so far:
flexbox.js:
const sidebar = (props) => (
<div>
<div className="container">
<div className="flex-item item-1" onClick={}>John Smith</div>
<div className="flex-item item-2">Male, 26 years old</div>
<div className="flex-item item-3">Overview</div>
<div className="flex-item item-4">Alerts</div>
<div className="flex-item item-5">Recent</div>
<div className="flex-item item-6">Blood Pressure</div>
<div className="flex-item item-7">Body Weight</div>
<div className="flex-item item-8">Glucose</div>
<div className="flex-item item-9">SpO2</div>
<div className="flex-item item-10"><FontAwesomeIcon icon={faCog}/></div>
</div>
</div>
);
flexbox.css:
.container {
border: 2px solid #57c0e8;
background-color: #57c0e8;
margin-top: 4%;
float: left;
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
color:white;
display: flex;
flex-direction: column;
height:40rem;
width:15rem;
flex-wrap: wrap;
justify-content: flex-start;
align-items: flex-start;
font-size:0.9rem;
}
.flex-item{
margin-top: 2rem;
}
.item-2 {
margin-top: 0rem;
}
.item-3 {
margin-top: 5rem;
}
.item-10{
align-self:center;
}

If you really want to keep your code as it is now, you could simply add a class on each flex item and an onClick method to add a class on the selected item and remove the class on the others.
here is how you can do that :
const MyList = () => {
const setSelectedItem = e => {
Array.from(document.getElementsByClassName("item"))
.forEach(item => item.classList.remove("selected"));
e.target.classList.add("selected");
};
return (
<div>
<ul>
<li className="item" onClick={setSelectedItem}>
item 1
</li>
<li className="item" onClick={setSelectedItem}>
item 2
</li>
<li className="item" onClick={setSelectedItem}>
item 3
</li>
<li className="item" onClick={setSelectedItem}>
item 4
</li>
</ul>
</div>
);
};
But I suggest you to refactor your code to build your sidebar list dinamically, It will be way easier to manage. You can do it this way, with an array containing your data and looping over it :
import React, { Component } from "react";
import { render } from "react-dom";
import Hello from "./Hello";
import "./style.css";
const App = () => {
const data = [
{ name: "item 1", isSelected: false },
{ name: "item 2", isSelected: false },
{ name: "item 3", isSelected: false },
{ name: "item 4", isSelected: false }
];
const [items, setItems] = React.useState(data);
const setSelectedItem = selectedItem => {
const newItems = [...items];
newItems.forEach(item => {
item.isSelected = item.name === selectedItem.name;
});
setItems(newItems);
};
const buildList = () => {
return items.map(item => (
<li className={item.isSelected ? 'selected':''} onClick={() => setSelectedItem(item)}>
{item.name}
</li>
));
};
return <ul>{buildList()}</ul>;
};
render(<App />, document.getElementById("root"));
Then you only have to write the css on .selected:
li{
padding: 10px;
}
.selected{
background-color: lightskyblue;
border-radius: 50px 0 0 50px;
box-shadow: 2px 2px 5px lightgray;
}
Here is the repro on stackblitz.
Here is used a list but it changes nothing compared to you using flexbox.

Ok, so I'm thinking you could do it by making an active class in your css to make it white:
.sidebarActive {
background:#fff
...
...
}
Then, add a state to your component that can store a string (Or I guess it could be a number and your could store the index of the selected div). This would looks something like:
const sidebar = (props) => {
const [selectedDiv,setSelectedDiv] = React.useState(null)
return (
<div>
<div className="container">
<div className="flex-item item-1" onClick={}>John Smith</div>
...
</div>
</div>
)
}
Then, your onClick function needs to set the state to the correct div:
<div className="flex-item item-1" onClick={()=>setSelectedDiv('John Smith')}>John Smith</div>
And finally, you need to add a conditional to the classNames of the divs - to check if the state is selecting this div:
<div className={
selectedDiv === "John Smith"
?
"flex-item item-1 sidebarActive"
:
"flex-item item-1"
}
onClick={...}
>
John Smith
</div>
There are then many ways to optimise this - Like adding your divs into an array, so that you don't need to type "John Smith", "Overview", "Alerts" and all the rest of them multiple times.
But, this should be enough info to get you somewhere!
Hope it helps :)

Related

How can i create a new div when i onclick the button in React js?

code 1 component:-
const TableheaderText = props => {
//const [playlist, setPlaylist] = useState(props);
const [playlist, setPlaylist] = useState("playlist");
const [showing, SetShowing] = useState();
const [isActive, setActive] = useState(true);
//console.log(playlist);
useEffect(() => {
// setPlaylist(props);
SetShowing("PLAYLIST:");
setPlaylist(props.val);
}, [props])
return (
<div className="mainContent">
<div className="tableHeaderBody" >
<div className="TableText" >
<div id="HIDE">{showing}</div><div id="SHOW">{playlist}</div>
</div>
<div className="ClossIcon"><FaCircle style={{ color: "#FC0000", width: "10px", height: "10px", alignItems: "right" }} /></div>
</div>
</div>
)
}
code 2 component:-
<NavLink to={`/Table`} onClick={(e) => myClick(val, index)} >
<button className='notActive buttonLeft'
onClick={() => handleOnClick(index)} // pass the index
className={activeIndex === index ? "active" : "notActive"}>
{val}
</button>
</NavLink>
Right now i have one div and when i click the menu value then one div replace the name
but i want that when i click the 1 value its create one div and when click the 2 value its create second div with the name of 2 div and place right side of 1 div and so.. (if 3,4 value menu ..)
This may be one possible solution to achieve the desired objective (copied from OP's question):
i want that when i click the 1 value its create one div and when click
the 2 value its create second div with the name of 2 div and place
right side of 1 div and so..
Code Snippet
const {useState} = React;
const Thingy = () => {
const myDivs = [...Array(4).keys()].map(i => `My Div # ${i+1}`);
const [flipDivs, setFlipDivs] = useState([
...myDivs.map(
(text, id) => ({id, text, show: false})
)
]);
const handleClick = e => {
const idx = e.target.id;
const newArr = [...flipDivs];
newArr[idx].show = !flipDivs[idx].show;
setFlipDivs(newArr);
};
const myButtons = [...Array(4).keys()];
return (
<div>
<div class="allDivs">
<div> Fixed Div </div>
{
flipDivs.filter(({show}) => !!show).map(
({text, id, show}, idx) => (
<div
key={idx}
class="simpleMargin rightBorder"
>
{text}
</div>
)
)
}
</div>
<div class="buttons">
{myButtons.map(id => (
<button
id={id}
class="simpleMargin"
onClick={handleClick}
>
{flipDivs[id].show ? 'Hide' : 'Show'} Div # {id+1}
</button>
))}
</div>
</div>
);
};
ReactDOM.render(
<div>
DEMO
<Thingy />
</div>,
document.getElementById("rd")
);
.allDivs {
border: 2px solid black;
width: fit-content;
display: flex;
align-items: center;
margin: 10px 15px;
}
.simpleMargin { margin: 5px 10px; }
.rightBorder { border: 2px solid black; }
.buttons {
display: flex;
margin: 10px 5px;
}
<div id="rd" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
Explanation
simple, straightforward approach
Add a flag to determine which div needs to be rendered on which button click
On the click-handler, simply update the flag to show / hide div
For this you need to make a div element and whoe it conditionally ( with state declared with useState ) and then toggle the state on button click to show it. like :
{
showDiv ? <div></div> : null
}
Here showDiv is:
const [showDiv, setShowDiv] = useState (false)
Now toggle showDiv on button click to true. :)

Radio button style changes when clicked with React Hooks

I want the radio button to change when clicked. This is what i have now image
I want it to change to this when clicked
Here's my code: `
const [active, setIsActive] = useState(false)
<div className={`checkbox payment-radio-btn1 ${active ? "checkbox:hover" : "" }`}>
<input type="radio" value="paystack" name='payment' onChange={handleChange}/>
<label id='paystack'>Paystack (Debit/Credit Card)</label>
</div>
<div className={`checkbox payment-radio-btn2 ${active ? "checkbox:hover" : "" }`}>
<input type="radio" value="wallet" name='payment' onChange={handleChange}/>
<label id='wallet'>Pay with Wallet</label>
</div>
Here's my css code
.checkbox:hover{
border: 2px solid #00B6F0;
background: #FFFFFF;
}
.payment-radio-btn1{
position: absolute;
width: 406px;
height: 64px;
left: 10px;
top: 128px;
background: #F3F4F5;
box-shadow: 0px 24px 38px 3px rgba(0, 0, 0, 0.14);
border-radius: 4px;
margin-top: 20px;
margin-left: 6px;
display: flex;
}
One option is a custom Radio element that allows you to represent your radio buttons however you like. In this example we use two emoji, but you could use images, or SVG if you wanted.
function Radio({ checked, onClick, children, on = "✔️", off = "🟡" }) {
return <div className="radio" onClick={onClick}>
{checked ? on : off } {children}
</div>
}
We can use the Radio elements in our app like this.
function App() {
const [radio, selectRadio] =
useRadio(["paystack", "paypal", "wallet"], "paystack")
return <div>
<Radio checked={radio == "paystack"} onClick={selectRadio("paystack")}>
Paystack (Debit/Credit Card)
</Radio>
{/* more radio options ...*/}
</div>
}
This is made possible by writing useRadio which encodes the radio group logic nicely in a custom hook.
function useRadio(validStates, initState) {
const [state, setState] = React.useState(initState)
return [
state,
value => event =>
validStates.includes(value)
? setState(value)
: console.error(`invalid option: ${value}`)
]
}
Here's a minimal, verifiable example. Run it below and click some radio buttons to see the application state change.
function App() {
const [radio, selectRadio] = useRadio(["paystack", "paypal", "wallet"], "paystack")
return <div>
<Radio checked={radio == "paystack"} onClick={selectRadio("paystack")}>
Paystack (Debit/Credit Card)
</Radio>
<Radio checked={radio == "wallet"} onClick={selectRadio("wallet")}>
Pay with Wallet
</Radio>
<Radio checked={radio == "paypal"} onClick={selectRadio("paypal")}>
PayPal
</Radio>
<pre>{JSON.stringify({paymentOption: radio}, null, 2)}</pre>
</div>
}
function Radio({ checked, onClick, children, on = "✔️", off = "🟡" }) {
return <div className="radio" onClick={onClick}>
{checked ? on : off } {children}
</div>
}
function useRadio(validStates, initState) {
const [state, setState] = React.useState(initState)
return [
state,
value => event =>
validStates.includes(value)
? setState(value)
: console.error(`invalid option: ${value}`)
]
}
ReactDOM.render(<App/>, document.querySelector("#app"))
.radio { cursor: pointer; }
pre { padding: 0.5rem; background-color: #ffc; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

How can i hover in React using useState

I wanna toggle a class when hovering on a Container by changing the opacity from 0 to 1, I've used onmouseEnter and onMouseLeave Event to toggle the class, but when I console hover state I see that is changing from true to false when I hover but the class "Show" is not changing.
What do you think ?
<--Components-->
import React,{useState} from 'react';
import './MyWork.css';
import {Visibility, GitHub } from "#material-ui/icons";
const SingleProject = ({src, title}) => {
const [hover, isHover] = useState(false);
const showIcons = isHover ? "Show" : "";
return (
<div className="card-container" onMouseEnter={()=> isHover(true)} onMouseLeave={()=> isHover(false)}>
<img src={src} alt={title}/>
<h1 id="card-title">{title}</h1>
<div className={`Info ${showIcons}`}>
<div className="Icon">
<GitHub/>
</div>
<div className="Icon">
<Visibility/>
</div>
</div>
</div>
)
}
export default SingleProject;
<--- Css--->
.card-container {
height: 314px;
width: 500px;
cursor: pointer;
position : relative;
}
.Info {
position: absolute;
height: 100%;
width: 100%;
top:0;
left:0;
display:flex;
justify-content:center;
align-items: center;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
}
.Info.Show {
opacity: 1;
}
When assigning the value to showIcons, you need to use hover instead of isHover which is the setter function for that state.
Additionally, I recommend naming the setter function setHover to avoid confusion and be more semantic. You can also add conditional Show class like this, which is more concise:
iconst SingleProject = ({src, title}) => {
const [hover, setHover] = useState(false);
return (
<div
className="card-container"
onMouseEnter={()=> setHover(true)}
onMouseLeave={()=> setHover(false)}
>
<img src={src} alt={title}/>
<h1 id="card-title">{title}</h1>
<div className={`Info ${hover ? "Show" : ""}`}>
<div className="Icon">
<GitHub/>
</div>
<div className="Icon">
<Visibility/>
</div>
</div>
</div>
)
}
export default SingleProject;
You are using the setter instead of the state itself on your condition. Change isHover with hover like below:
const showIcons = hover ? "Show" : "";

How to update the state in different mobile screens using React Hooks

I am working on React project, In that I have a button under that I have another div, I written a function if My screen width is 320px then margin-bottom: 150px has to apply under button. it is working fine, but when I am in 320px screen if I click the button then under button margin-bottom: 150px is applied. Here the problem comes now when I go to 375 px here also margin-bottom: 150 px applied automatically. so someone help to how to update state in 375px. Because in 375px screen I have to apply margin-bottom: 300 px.
If you have any questions please let me know thank you.
This is My code
This is App.js
import React, { useState, useLayoutEffect } from 'react';
import './App.css';
const App = () => {
const [style, setStyle] = useState(null)
function useMediaQuery() {
const [screenSize, setScreenSize] = useState([0]);
useLayoutEffect(() => {
function updateScreenSize() {
setScreenSize([window.innerWidth]);
}
window.addEventListener("resize", updateScreenSize);
updateScreenSize();
return () => window.removeEventListener("resize", updateScreenSize);
}, []);
return screenSize;
}
const [mediaQuery] = useMediaQuery();
console.log(mediaQuery, '***')
const applyStyle = () => {
if(mediaQuery === 320) {
setStyle({
marginBottom: '150px'
})
}
}
return (
<div className='container'>
<div className='row'>
<div className='col-12'>
<div className='first'>
<button onClick={applyStyle} style={style} className='btn btn-primary'>Click here</button>
<span className='closeWindow'><i className="far fa-window-close"></i></span>
</div>
<div className='second'>
</div>
</div>
</div>
</div>
)
}
export default App
in App.css write a #media query:
#media screen and (max-width: 375px) {
button {
margin-bottom: 300px;
}
}
You can apply media queries in React either programmatically, or using css.
Option 1, using css:
.myButton{
/* media queries */
#media (max-width: 320px) {
margin-bottom: 150px;
}
#media (max-width: 375px) {
margin-bottom: 300px;
}
}
and then:
return (
<div className='container'>
<div className='row'>
<div className='col-12'>
<div className='first'>
<button onClick={applyStyle} className='myButton btn btn-primary'>Click here</button>
<span className='closeWindow'><i className="far fa-window-close"></i></span>
</div>
<div className='second'>
</div>
</div>
</div>
</div>
)
Option 2, programmatically:
import React, { useState, useEffect, useLayoutEffect } from 'react';
import './App.css';
const App = () => {
const [mediaMatch, setMediaMatch] = useState();
const handler = e => setMediaMatch(e.matches);
useEffect(() => {
window.matchMedia('(min-width: 768px)').addListener(handler);
return () => {
window.removeEventListener(handler);
};
}, []);
return (
<div className="container">
<div className="row">
<div className="col-12">
<div className="first">
<button
onClick={applyStyle}
style={{
marginBottom: mediaMatch ? '300px' : '150px'
}}
className="btn btn-primary"
>
Click here
</button>
<span className="closeWindow">
<i className="far fa-window-close" />
</span>
</div>
<div className="second" />
</div>
</div>
</div>
);
};

REACT.JS: How to loop over all NavBar buttons and remove their class and add "active" class to the clicked button

I am trying to make a simple NavBar with React.js. The problem I found myself in is the looping over all nav buttons and remove the "active" className and then add "active" to just that one clicked button.
I managed to make a state that toggles "active" to true on the clicked element which then in the className attribute does this If statement:
className={this.state.active ? "nav-item nav-link active" : "nav-item nav-link"}
Here is the full code:
import React, { Component } from 'react';
class NavButton extends Component {
state = {
active: false
}
setActive = () => {
this.setState({
active: !this.state.active
})
}
render() {
return (
<a
className={this.state.active ? "nav-item nav-link active" : "nav-item nav-link"}
href={this.props.href}
onClick={this.setActive}> {this.props.title}
</a>
)
}
}
class NavBar extends Component {
buttons = [
{
title: "Home",
key: 0
},
{
title: "Team",
key: 1
},
{
title: "Discord",
key: 2
},
{
title: "Gallery",
key: 3
},
{
title: "Download",
key: 4
}
]
render() {
return (
<nav className="navbar" id="navbarMain">
<div></div>
<div className="navbar-nav flex-row">
{this.buttons.map(button => <NavButton title={button.title} key={button.key} />)}
</div>
<div></div>
</nav>
)
}
}
export default NavBar
This works, for just one element (don't mind that the active state goes false when it's true. The problem is, how would I do it in the React way to remove the active className in all other buttons?
With plain JS i have no issues to do that, i just loop over all elements that have the className "navbar-item" and set their classnames to be without the "active" one then add " active" to the pressed element like in this example https://www.w3schools.com/howto/howto_js_tabs.asp
Would you guys be able to help and tell me what would be the best react way to do this?
Much appreciated!
A common pattern for these use-cases is to keep the relevant state in the parent, so that it is the parent (NavBar) that keeps track of which child (NavButton) is "active". The NavButton can then become a stateless component which takes "active" as a prop.
const NavButton = ({active, title, href, onSetActive}) => {
return (
<button
className={active ? "nav-item nav-link active" : "nav-item nav-link"}
href={href}
onClick={onSetActive} >
{title}
</button>
)
}
class NavBar extends React.Component {
constructor(props) {
super(props);
this.state = {
activeIndex: 0, // keep the active index in state
buttons: [
{
title: "Home",
key: 0
},
{
title: "Team",
key: 1
},
{
title: "Discord",
key: 2
},
{
title: "Gallery",
key: 3
},
{
title: "Download",
key: 4
}
]
}
}
handleChangeActive(newActiveIndex) {
this.setState({activeIndex: newActiveIndex});
}
render() {
const {activeIndex} = this.state;
return (
<nav className="navbar" id="navbarMain">
<div></div>
<div className="navbar-nav flex-row">
{this.state.buttons.map((button, buttonIndex) =>
/* determine which nav button is active depending on the activeIndex state */
<NavButton onSetActive={ () => this.handleChangeActive(buttonIndex)} active={buttonIndex === activeIndex } title={button.title} key={button.key} />)}
</div>
<div></div>
</nav>
)
}
}
ReactDOM.render(<NavBar />, document.querySelector("#app"));
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.done {
color: rgba(0, 0, 0, 0.3);
text-decoration: line-through;
}
input {
margin-right: 5px;
}
.nav-item.nav-link {
background: grey;
}
.nav-item.nav-link.active {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<body>
<div id="app"></div>
</body>
I would move your state and logic to the NavBar component. It would be responsible to store and set the current active button, and pass it as prop to all buttons.
class NavBar extends Component {
state = {
activeButtonIndex: null;
}
buttons = [
{
title: "Home",
key: 0
},
{
title: "Team",
key: 1
},
];
renderButton = (button, index) => (
<NavButton
{...button}
isActive={this.state.activeButtonIndex === index}
setActive={() => this.setState({ activeButtonIndex: index })}
/>
);
render() {
return (
<nav className="navbar" id="navbarMain">
<div className="navbar-nav flex-row">
{this.buttons.map((button, index) => this.renderButton(button, index)}
</div>
</nav>
);
}
}
const NavButton = ({ isActive, setActive, href, title }) => (
<a
className={isActive ? "nav-item nav-link active" : "nav-item nav-link"}
href={href}
onClick={setActive}
>
{title}
</a>
);

Resources