I am trying to make onClick() function work for every button (its the same result), but as of now onClick() works only once.
If I click on a button again (the same or different) the pop up doesn't work anymore.
Could you please help? I cannot figure out how to fix it.
function Challange() {
const [isPopped, setPop] = useState(false);
const pop = () => {
setPop(true);
};
return (
<>
{isPopped && <Dialog2 />}
<div className="challanges">
<h1 className="newchallenge">Choose New Challange</h1>
<button className="challangeBtn" onClick={pop}>
Eat Vegetarian (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Take the bike to work (14days)
</button>
<button className="challangeBtn" onClick={pop}>
Recycle your plastic bottles (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Use public transport to commute (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Don't fly an airplane (365days)
</button>
</div>
</>
);
}
export default Challange;
Your pop function code only sets the state to true, so it will never be false again. You may change it like this.
const pop = () => {
setPop(!isPopped);
};
in your case setPop can take boolean value OR method that returns boolean.
Best practices for handle toggling in React looks like:
const pop = () => {
setPop(currentValue => !currentValue);
};
Also, use useCallback hook to manage events like click and avoid re-initialization of your method on each render:
const pop = useCallback(() => {
setPop(currentValue => !currentValue);
}, []);
Related
The problem is...
The first popup renders fine.
But when I try to render the second popup, it's not working.
A new popup is not invoked, the previous popup is refreshed.
I want to call a new popup when I clicked a cell in the grid.
my code is like this
const Main = () => {
const [isPopupOpen, setIsPopupOpen] = useState(false);
return (
<>
... other components (including grid)
{ isPopupOpen && <Popup />}
</>
)
};
when Grid is Clicked, 'isPopupOpen' is updated to true.
I use 'react-new-window' library, and this library use 'window.open()' ((https://github.com/rmariuzzo/react-new-window)
so I set different window names to call several popups.
but I can't solve the problem.
I try to set a state object that has a boolean value.
const [popupObj, setPopupObj] = useState({});
when the grid is clicked, popupObj updates like
{'cellA': true, 'cellD': true}
and a return statement is like
{popupObj[cellName] && <Popup /> }
but the result was the same.
what should I do to solve this problem?
I wrote an example for you. Hope it helps.
use popupIds state to store the popups that you want to open
use Set to toggle the popupIds in the addPopup click handler
import * as React from "react";
export default function App() {
const [popupIds, setPopupIds] = React.useState([]);
const addPopup = (popupId) => {
const set = new Set(popupIds);
if (set.has(popupId)) {
set.delete(popupId);
} else {
set.add(popupId);
}
setPopupIds(Array.from(set));
};
return (
<div className="App">
{["hello", "react"].map((popupId) => (
<div onClick={() => addPopup(popupId)}>{popupId}</div>
))}
{popupIds.map((popupId) => (
<Popup title={getPopupTitle(popupId)} />
))}
</div>
);
}
const getPopupTitle = (popupId) => `title for ${popupId}`;
const Popup = ({ title }) => <div>{title}</div>;
Here is a codesandbox that you can play with directly.
You need to add your popup in an array, so you can render many popup as you want, then you need to define in How much time you will remove a added popup from array or add a close button
Extra: you can configure in global state to access in all your application to your popups and you will have a component like this: https://www.npmjs.com/package/notistack
I built this toy problem to replicate an issue I am facing in a larger app. Why does handleClick not fire when the button is clicked?
const Button = () => <button type="button">Click me</button>;
export const App = () => {
const handleClick = () => {
console.log("clicked");
};
return <Button onClick={handleClick} />;
};
You pass onClick={handleClick} as a property to Button but the Button component does not use the property.
const Button = () ... // ⚠️ no onClick property used
You can fix this by responding to the onClick property -
const Button = ({ onClick }) => // ✅
<button type="button" onClick={onClick}> // ✅
Click me
</button>
An obvious improvement would be to respond to the children property as well. This allows the caller of Button to write anything in place of the static Click me -
const Button = ({ onClick, children }) =>
<button type="button" onClick={onClick}>{children}</button>
<Button onClick={handleRegister}>Register</Button>
<Button onClick={handleLogin}>Login</Button>
<Button onClick={handleSave}>Save</Button>
Note children can be passed as a property. Sometimes you will see components use children in this way. Both examples function identically -
const Button = ({ onClick, children }) =>
<button
type="button"
onClick={onClick}
children={children}
/>
Another common thing for Button components like this is to automatically prevent the default event for the onClick handler. We can also accept a type property and set the default to "button" if the caller does not otherwise specify -
const Button = ({ type = "button", onClick, children, preventDefault = true }) =>
<button
type={type}
onClick={e => {
if (preventDefault) e.preventDefault()
onClick(e)
}}
children={children}
/>
<Button type="submit" onClick={handleRegister}>Register</Button>
<Button onClick={handleReset} preventDefault={false} children="Reset" />
const NewApp = (props) => {
const [ counter, setCounter ] = useState(0)
const incrementCounterByOne = () => setCounter(counter + 1)
const decrementCounterByOne = () => setCounter(counter - 1)
const setCounterToZero = () => setCounter(0)
return (
<div>
<Display counter={counter} />
<Button handleClick={incrementCounterByOne} text="Increment" />
<Button handleClick={decrementCounterByOne} text="Decrement" />
<Button handleClick={setCounterToZero} text="Reset" />
{/* <button onClick={incrementCounterByOne}>Increment</button>
<button onClick={decrementCounterByOne}>Decrement</button>
<button onClick={setCounterToZero}>Reset</button> */}
</div>
)
}
const Button = (props) => {
console.log("clicked")
return (
<button onClick={props.handleClick}>
{props.text}
</button>
)
}
I am a newbie in react. When I am clicking on any button the button function is getting called three times but I am only clicking on one button at a time. I am a little confused on why so. If anyone can explain the process of how this is happening it be very helpful thank you!
Your console.log("clicked") runs when a Button is called:
const Button = (props) => {
console.log("clicked")
and you have three buttons, so you see three logs whenever there's a re-render.
If you wanted to log only when a click occurs (and only log once, not three times), log inside the click handler instead.
<button onClick={(e) => {
console.log('clicked');
return props.handleClick(e);
}}>
I am trying to show a dialog box based on the data returned from apollo hook, where I would have to check that one of the values matches an id.
When checker===true I want the dialog to open on render and when the user clicks the Close button, the dialog should close.
const DialogComponent = () => {
const {data, loading, error} = useQuery(GET_QUERY_DATA)
const [isDialogOpen, setIsDialogOpen] = useState(false);
const checker = data && data.getData.some((item_data.id === id))
const closeDialog = () => {
setIsDialogOpen(false)
}
if(checker) {
setIsDialogOpen(true)
}
return(
<Dialog
open={isDialogOpen}
close={closeDialog}>
// dialog content here
<DialogActions>
<Button onClick={closeDialog}> Close </Button>
</DialogActions>
</Dialog>
)}
The above errors with too many re-renders.
I have tried a conditional render instead however, seems that the Dialog component never opens even when checker===true (below).
const DialogComponent = () => {
const {data, loading, error} = useQuery(GET_QUERY_DATA)
const [isDialogOpen, setIsDialogOpen] = useState(false);
const checker = data && data.getData.some((item_data.id === id))
const closeDialog = () => {
setIsDialogOpen(false)
}
if(checker) {
setIsDialogOpen(true)
}
return(
{checker && <Dialog
open={isDialogOpen}
close={closeDialog}>
// dialog content here
<DialogActions>
<Button onClick={closeDialog}> Close </Button>
</DialogActions>
</Dialog>
)}}
I have also tried replacing the open prop value with checker I.e. open={checker} however, then the Dialog box never can be closed even when clicking the Close button.
Any help appreciated.
The close button does close the dialog, it is being opened again on the next render with
if(checker) {
setIsDialogOpen(true)
}
you could do:
<Dialog
open={isDialogOpen && checker}
close={closeDialog}>
<DialogActions>
<Button onClick={closeDialog}> Close </Button>
</DialogActions>
</Dialog>
One problem I see in your code is regarding this part:
if (checker) {
setIsDialogOpen(true)
}
Every time a state is updated in a component, the component funcion is called again to re-render it with the updated state. So the snippet above is executed again and if checker is true, the state is updated again, then it keeps re-redering again and again.
Try wrapping the snippet above inside a React.useEffet() like this:
React.useEffect(() => {
setIsDialogOpen(checker)
}, [checker])
I'm relatively new to React and I was working on a button that duplicates a component I created when clicked, but I want to limit the user to only be allowed to click on said button a set number of times (say 4 times) before the button is non-functional/removed. Here's a code snippet if it helps; is this possible? I thought about having a counter, but how would I implement that alongside the button?
Many thanks!
function App() {
const [inputList, setInputList] = useState([]);
const onAddBtnClick = event => {
setInputList(inputList.concat(<Autocomplete items={foods} />));
};
return (
<Fragment>
<div className="foodcompleter">
<Button onClick={onAddBtnClick} variant="primary" size="lg" block>Add Food</Button>
{inputList}
</div>
</Fragment>
);
}
You can basically check if inputList.length === 4, then you disable the button
You can create your component CustomButton with a state that saves the number of clicks and after each state change just validate if the number of clicks is equal to your desired value.
You could remove the event listener after the click
const onKeyDown = (event) => { console.log(event) }
useEffect(() => {
window.addEventListener('keydown', onKeyDown)
return () => { window.removeEventListener('keydown', onKeyDown) }
}, [])