I have recreated the radio button behavior in Sandbox.
When one button is active, all the other ones should be inactive.
Please find the link here :
https://codesandbox.io/s/amazing-chaplygin-xf8el?fontsize=14
For 3 buttons I have created 3 functions. Is there a way to optimize my code with 1 single function ?
Thank you
Yes, you can do that by using an Array:
import React, { useState } from "react";
export default function ButtonToggle() {
const [happy, setHappy] = useState([false, false, false]);
function handle(idx) {
let set = [false, false, false];
set[idx] = !happy[idx];
setHappy(set);
}
return (
<div>
{happy[0] ? "😄" : "🤕"}
<button
onClick={() => {
handle(0);
}}
>
bouton1
</button>
{happy[1] ? "😄" : "🤕"}
<button
onClick={() => {
handle(1);
}}
>
bouton2
</button>
{happy[2] ? "😄" : "🤕"}
<button
onClick={() => {
handle(2);
}}
>
bouton3
</button>
</div>
);
}
CodeSandbox: https://codesandbox.io/s/jolly-haibt-73df1
Related
I have created a carousel which is a column of ten dates ,for this i am mapping dates by momentjs, Inside each of this column , i am mapping different time slots for morning ,afternoon and evening,
and i have a functionality that only shows first two time slots and then there is a show more button, by clicking on this button more time slots are appear,but whenver i am clicking on this button all of the columns time slots is appearing, i have to handle all the column button individually..
Thank You in adavance... :)
below is my code...
const [showMoreClicked, setShowMoreClicked] = useState(false);
const [showMoreAfternoon, setShowMoreAfternoon] = useState(false);
const [showMoreEvening, setShowMoreEvening] = useState(false);
const showMoreSlotsForMorning = (e) => {
e.preventDefault();
setMoreClicked(!showMoreClicked);
};
const showMoreSlotsForAfternoon = (e) => {
e.preventDefault();
setShowMoreAfternoon(!showMoreAfternoon);
};
const showMoreSlotsForEvening = (e) => {
e.preventDefault();
setShowMoreEvening(!showMoreEvening);
};
<Carousel responsive={responsive}>
{nexttendates.map((elem, dateIndex) => {
return (
<div>
<button key={dateIndex} className="nexttendates">
{elem}
</button>
<div className="appointment-timelots">
<div className="availableslots">
<div className="availableslot">
<img
src="../elements/doctorlist/doctorcard/sunrise.png"
alt=""
className="sunrise"
/>
Morning
</div>
</div>
</div>
{morningtime.map((elem, morInd, arr) => {
if (showMoreClicked == false) {
while (morInd == 0 || morInd == 1)
return (
<button key={morInd} className="appointtimes">
{elem}
</button>
);
} else {
return (
<button key={morInd} className="appointtimes">
{elem}
</button>
);
}
})}
<button
choseIndex={dateIndex}
onClick={showMoreSlotsForMorning}
className="appointtimes"
>
{showMoreClicked ? "Show Less" : "Show More"}
</button>
<img
src="../elements/doctorlist/doctorcard/sun.png"
alt=""
className="afternoon"
/>
Afternoon
{afternoontime.map((elem, aftInd) => {
if (showMoreAfternoon == false) {
while (aftInd == 0 || aftInd == 1)
return (
<button className="appointtimes">{elem}</button>
);
} else {
return (
<button className="appointtimes">{elem}</button>
);
}
})}
<button
choseIndex={dateIndex}
onClick={showMoreSlotsForAfternoon}
className="appointtimes"
>
{showMoreAfternoon ? "Show Less" : "Show More"}
</button>
<img
src="../elements/doctorlist/doctorcard/night-mode.png"
alt=""
className="evening"
/>
Evening
{eveningtime.map((elem, eveInd) => {
if (showMoreEvening == false) {
while (eveInd == 0 || eveInd == 1) {
return (
<button className="appointtimes">{elem}</button>
);
}
} else {
return (
<button className="appointtimes">{elem}</button>
);
}
})}
<button
choseIndex={dateIndex}
onClick={showMoreSlotsForEvening}
className="appointtimes"
>
{showMoreEvening ? "Show Less" : "Show More"}
</button>
</div>
);
})}
</Carousel>
i think its happening because of i have mapped an array and only used one useState to check open or not...Can anybody plz help me....
Make the time slots list as a separate component, so that each of the morning, afternoon, and evening list will have their own state automatically for toggling display.
Something like this example:
import { useState } from "react";
// Toggle showMore value on click
const SlotsList = ({ slots }) => {
const [showMore, setShowMore] = useState(false);
const handleShowMoreClick = () => {
setShowMore((prev) => !prev);
};
// Filter the slots prop before map it if showMore is false
return (
<div>
{slots
.filter((elem, index) => (showMore ? true : index <= 1))
.map((elem, index) => (
<button key={index} className="appointtimes">
{elem}
</button>
))}
<button onClick={handleShowMoreClick} className="appointtimes">
{showMore ? "Show Less" : "Show More"}
</button>
</div>
);
};
export default SlotsList;
In this example, the list is filtered before being mapped out for an easier solution. The key property should be replaced by a unique ID to avoid conflict.
It can then be imported and used like below in the main component. Also reusable for all 3 lists, and each have separate display toggle.
<SlotsList slots={morningtime} />
I'm a newbie in react. I have two class in css file. One is btn and another is active. I want to set an active class to the first button by default and when I click on other buttons it'll be remove and add to the current button. I'll be thankful if anyone help me about this. Thanks in advance.
Here is my codes
import React, {useState} from 'react';
const Tab = () => {
const [tabBtn, setTabBtn] = useState(false);
const handleBtn = () => {
setTabBtn(true);
}
return (
<div className='btnContainer'>
<button className={"btn" + (tabBtn ? " active" : "")} onClick={handleBtn}>One</button>
<button className='btn'>Two</button>
<button className='btn'>Three</button>
<button className='btn'>Four</button>
<button className='btn'>Five</button>
<button className='btn'>Six</button>
<button className='btn'>Seven</button>
</div>
);
}
export default Tab;
Use this code :
className={`btn ${tabBtn ? " active" : ""}`}
So let's make a few optimizations here:
First let's put an array of all your buttons and then use state to track which one is selected.
import React, {useState} from 'react';
const buttonList = ['One', 'Two', 'Three', 'Four'];
const Tab = () => {
const [tabBtn, setTabBtn] = useState('One');
return (
<div className='btnContainer'>
{
buttonList.map(b => {return (
<button
className={b === tabBtn ? 'active' : '' }
key={`${b}Button`}
onClick={() => setTabBtn(b)}
>
{b}
</button>)}
)}
</div>
);
}
export default Tab;
Without map
import React, {useState} from 'react';
const Tab = () => {
const [tabBtn, setTabBtn] = useState('One');
return (
<div className='btnContainer'>
<button
className={'One' === tabBtn ? 'active' : '' }
key={`One Button`}
onClick={() => setTabBtn('One')}
>
One
</button>
<button
className={'Two' === tabBtn ? 'active' : '' }
key={`Two Button`}
onClick={() => setTabBtn('Two')}
>
Two
</button>
</div>
);
}
export default Tab;
Obviously, add in the rest of the buttons up to 7.
I'm trying to build a map that will show whisky distilleries as icons on the map. When one of the distillery markers is clicked, the state is updated to hold an object with that distillery data so a popup can render with relevant info. I've got a hover effect that I want to persist after clicking for as long as the state holds the obj.
I have the following ternary operator that should add 'clicked' when selectedDistillery is truthy, but the class is not applied.
className={`marker-btn ${selectedDistillery ? 'clicked' : ''}`}
The popup renders fine on click so not really sure what the issue is.
Here's the entire component
import 'mapbox-gl/dist/mapbox-gl.css';
import './App.css';
import React, { useState, useEffect } from 'react'
import ReactMapGl, { Marker, Popup } from "react-map-gl";
import * as distilleries from "./data/dist-locations.json";
const App = () => {
const [viewport, setViewport] = useState({
latitude: 56.770720743612365,
longitude: -4.2724397531559655,
width: "90vw",
height: "90vh",
zoom: 6,
});
const [selectedDistillery, setSelectedDistillery] = useState(null);
useEffect(() => {
const listener = (e) => {
if(e.key === 'Escape'){
setSelectedDistillery(null);
}
}
window.addEventListener('keydown', listener);
return () => {
window.removeEventListener('keydown', listener);
}
}, [])
console.log(selectedDistillery);
return (
<div className="main-container">
<div className="map-container">
<ReactMapGl
{...viewport}
mapboxApiAccessToken={process.env.REACT_APP_API_KEY}
onViewportChange={(viewport => { setViewport(viewport) })}
mapStyle="mapbox://styles/vdiad/ckkq0g4201s4r17peswejsg82"
>
{distilleries.features.map(distillery => {
return(
<Marker key={distillery.id} latitude={distillery.geometry.coordinates[1]} longitude={distillery.geometry.coordinates[0]} >
<button
className={`marker-btn ${selectedDistillery ? 'clicked' : ''}`}
onClick={()=>{
setSelectedDistillery(distillery);
}}
>
<img src="/barrel1.svg" alt="whisky barrel img" />
</button>
</ Marker>
)
})}
{selectedDistillery && (
<div className="popup">
<Popup
latitude={selectedDistillery.geometry.coordinates[1]}
longitude={selectedDistillery.geometry.coordinates[0]}
onClose={()=>{setSelectedDistillery(null)}}
>
<h3>{selectedDistillery.properties.NAME}</h3>
<p>Founded in: </p>
<p>Region: </p>
</ Popup>
</div>
)}
</ReactMapGl>
</div>
</div>
)
}
export default App
I am about to make a function where you can choose sizes. It works when you use just JavaScript with HTML. Is my syntax from the JavaScript function correct? Because I am getting an Error from Next.js.
Here is the error message I am getting from Next.js.
import React from "react";
const ChangeSize = () => {
const sizes = document.querySelectorAll(".size");
function changeSize() {
sizes.forEach((size) => size.classList.remove("active"));
this.classList.add("active");
}
sizes.forEach((size) => size.addEventListener("click", changeSize));
return (
<div className='size-container'>
<h3 className='title'>size</h3>
<div className='sizes'>
<span className='size'>7</span>
<span className='size'>8</span>
<span className='size active'>9</span>
<span className='size'>10</span>
<span className='size'>11</span>
</div>
</div>
);
};
export default ChangeSize;
normally you wouldn't use the JavaScript DOM API to accomplish this type of task in React. The function and JSX would resemble something like this in a React Function component:
const SizeSwitcher = () => {
const [activeLink, setActiveLink] = React.useState(9); // 9 was default in example
return (
<div className='size-container'>
<h3 className='title'>size</h3>
<div className='sizes'>
<span onClick={() => setActiveLink(7)} className={`size ${activeLink === 7 ? 'active' : ''}`}>7</span>
<span onClick={() => setActiveLink(8)} className={`size ${activeLink === 8 ? 'active' : ''}`}>8</span>
<span onClick={() => setActiveLink(9)} className={`size ${activeLink === 9 ? 'active' : ''}`}>9</span>
<span onClick={() => setActiveLink(10)} className={`size ${activeLink === 10 ? 'active' : ''}`}>10</span>
<span onClick={() => setActiveLink(11)} className={`size ${activeLink === 11 ? 'active' : ''}`}>11</span>
</div>
</div>
);
};
export default SizeSwitcher;
You can state up some state and then use that piece of state to determine if the active class should be present. Next steps could be figuring out how to reduce the code duplication in the example. Hope this helps!
Edit - Oh yeah if you are using Next.js you can leave out the React import at the top. That is handled by Next automatically.
I have five buttons, dynamically created. My target is: when any button is clicked to add active class to it, and of course if any other has that active class to remove it. How can I achieve that?
<div>
{buttons.map(function (name, index) {
return <input type="button" value={name} onClick={someFunct} key={ name }/>;
})}
</div>
You need to introduce state to your component and set it in onClick event handler. For example output of render method:
<div>
{buttons.map(function (name, index) {
return <input
type="button"
className={this.state.active === name ? 'active' : ''}
value={name}
onClick={() => this.someFunct(name)}
key={ name } />;
})}
</div>
event handler (element method):
someFunct(name) {
this.setState({ active: name })
}
One of the easiest way to add active class is setting state and changing that state on each switch, by the state value you can change the active class of the item.
I also had an same issue with switching the active class in list.
Example:
var Tags = React.createClass({
getInitialState: function(){
return {
selected:''
}
},
setFilter: function(filter) {
this.setState({selected : filter})
this.props.onChangeFilter(filter);
},
isActive:function(value){
return 'btn '+((value===this.state.selected) ?'active':'default');
},
render: function() {
return <div className="tags">
<button className={this.isActive('')} onClick={this.setFilter.bind(this, '')}>All</button>
<button className={this.isActive('male')} onClick={this.setFilter.bind(this, 'male')}>male</button>
<button className={this.isActive('female')} onClick={this.setFilter.bind(this, 'female')}>female</button>
<button className={this.isActive('child')} onClick={this.setFilter.bind(this, 'child')}>child</button>
<button className={this.isActive('blonde')} onClick={this.setFilter.bind(this, 'blonde')}>blonde</button>
</div>
}
});
hope this will help you!
One of the easiest solution for adding active class to the current button (highlight it) for react developers.
const {useState,Fragment} = React;
const App = () => {
const [active, setActive] = useState("");
const handleClick = (event) => {
setActive(event.target.id);
}
return (
<Fragment>
<button
key={1}
className={active === "1" ? "active" : undefined}
id={"1"}
onClick={handleClick}
>
Solution
</button>
<button
key={2}
className={active === "2" ? "active" : undefined}
id={"2"}
onClick={handleClick}
>
By
</button>
<button
key={3}
className={active === "3" ? "active" : undefined}
id={"3"}
onClick={handleClick}
>
Jamal
</button>
</Fragment>
);
}
ReactDOM.render(
<App/>,
document.getElementById("react")
);
.active{
background-color:red;
}
<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="react"></div>