Why my onclick getting called on each render in react js? - javascript

I am making a react application and on every render my variable gets changed even if the state change logic is inside a onClick function.
Here's my code:
constructor() {
super();
this.state = {
options: [],
suboptions: [],
saveflag:false
};
}
<div>
{
console.log(this.state.saveflag),
saveflag?<></>:
<button
type="button"
className="btn"
onClick={() => this.props.data.handleApiGrants(apis),this.setState({saveflag:true})}
>
Save
</button>}
</div>
</div>
Above I have set the flag saveflag to false initially and I want to change it on click of the save button but its getting changed on every render.
Can someone help?

you have a problem with syntax, now it will work:
onClick={() => {
this.props.data.handleApiGrants(apis);
this.setState({ saveflag: true });
}}

preventDefault should help:
onClick={e => {
e.preventDefault();
this.props.data.handleApiGrants(apis);
this.setState({saveflag:true});
}}

Related

How can I setState() another input value with a button in the same component in React?

How can I setState() another input value with a button in the same component in React?
I'm using the onClick event handler on the button.
I want to make the handleClickfunction which I gave it to the button, to target the value of the input
class Search extends Component {
state = {
searchInput: "",
};
handleClick = () => {
this.setState({
searchInput: input.value,
});
};
render() {
return (
<div>
<input type="text"/>
<button onClick={this.handleClick}>Enter</button>
</div>
);
}
}
Your question is not clear, I believe you are asking how to set the value of an input field when you press a button in react.
If that is correct, then you have done most of the work already, all you need to do now is add an <input> tag.
Like this:
<input type="text" value={ this.state.searchInput } />
If I have misunderstood your question then please clarify.
It may be worth reading about how State and Lifecycle work in React Here
Whenever the setState() function is triggered, React automatically runs the render() function in any components where state has changed, rerendering that component with the new state values.
Edit
After clarification I now understand exactly what you want.
You require the use of a ref, like this:
class Search extends Component {
state = {
searchInput: "",
};
handleClick = () => {
this.setState({
searchInput: this.inputText,
});
};
render() {
return (
<div>
<input type="text" ref={(x) => this.inputText = x}/>
<button onClick={this.handleClick}>Enter</button>
</div>
);
}
}
instead of using a button to update the state try this:
<input type="text" onChange={(e) => this.setState({searchInput: e.target.value }) />

Pass prop value as a parameter in an arrow function in an event handler onClick() in React

I'm trying to pass a value of prop in a function which is invoked on onClick(), but I'm getting the following error when I try to console.log() that value inside the function.
Error:
**Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property nativeEvent on a
released/nullified synthetic event. This is set to null. If you must
keep the original synthetic event around, use event.persist().
class Calculator extends React.Component {
constructor(props) {
super(props);
this.evaluateInfixString = this.evaluateInfixString.bind(this);
this.appendInfixString = this.appendInfixString.bind(this);
this.state = {
buttons: ["+", "-", "*", "/", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, "clear", "="],
infixString: null
};
}
evaluateInfixString() {
console.log("perform operation");
}
appendInfixString(buttonPressed) {
console.log(buttonPressed);
}
render() {
return (
<div id={"calculator"}>
<Display value={this.state.infixString} />
<Buttons
buttons={this.state.buttons}
appendInfixString={this.appendInfixString}
/>
</div>
);
}
}
class Display extends React.Component {
render() {
return <div id={"display"}>{this.props.value}</div>;
}
}
class Buttons extends React.Component {
render() {
return (
<div id={"buttons"}>
{this.props.buttons.map(button => {
return <button className={"button"} onClick={(button) => this.props.appendInfixString(button)}>{button}</button>;
})}
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Calculator />, rootElement);
Change:
return <button className={"button"} onClick={(button) => this.props.appendInfixString(button)}>{button}</button>;
To:
return <button className={"button"} onClick={() => this.props.appendInfixString(button)}>{button}</button>;
Here's a working codepen. If you open the console, you'll see that the number or character is logged to the console for you.
Another way to accomplish what you'd like to do would be something like what I've done in this codepen. You'll be passing the event back to the parent and then you can access the value with e.target.value like I've shown in your parent component. In that case, you're child component would have a click handler like this:
<button type="button" className={"button"} value={button} onClick={this.props.appendInfixString}>{button}</button>
The button value will be passed back with the event in the parent click event handler, which you can access there.
What is passed to onClick is click event, so in your code below
<button className={"button"} onClick={(button) =>this.props.appendInfixString(button)}>{button}</button>
what you pass to the appendInfixString is not the button string that the user clicks, but rather the click event. If you need to pass the button string being clicked, try
<button className={"button"} onClick={() => this.props.appendInfixString(button)}>{button}</button>

setState() does not change state when called from element that depends on state to render

I have a little component like this (Code below is simplified to the parts needed) that behaves very strange when it comes to updating the state.
class Componenent extends React.Component {
constructor(props) {
super(props);
this.state = {showStuff: false};
}
render() {
return(
//Markup
{this.state.showStuff && (
<button onClick={() => this.setState({showStuff: false})} />
)}
// More Markup
);
}
}
The state gets updated somewhere else in the component, so the prop is true when the button is clicked.
A click also triggers the setState function (callback gets executed), however the state does not update.
My guess is that it does not update because the function is called by an element that directly depends on the state prop to be visible.
I figured out that adding another prop test: true to the state and changing that property to false when the button is clicked also triggers the showStuff prop to change to false. So it works when I make strange hacks.
Can someone explain this weird behavior to me? I can't gasp why the above snippet does not work like intended.
Here is the entire component:
class ElementAdd extends React.Component {
constructor(props) {
super(props);
this.defaultState = {
showElementWheel: false,
test: true
};
this.state = this.defaultState;
}
handleAddCardClick() {
if (this.props.onCardAdd) {
this.props.onCardAdd({
type: ElementTypes.card,
position: this.props.index
});
}
}
handleAddKnowledgeClick() {
if (this.props.onCardAdd) {
this.props.onCardAdd({
type: ElementTypes.knowledge,
position: this.props.index
});
}
}
handleTabPress(e) {
if (e.key === 'Tab') {
e.preventDefault();
let target = null;
if (e.shiftKey) {
if (e.target.previousSibling) {
target = e.target.previousSibling;
} else {
target = e.target.nextSibling;
}
} else {
if (e.target.nextSibling) {
target = e.target.nextSibling;
} else {
target = e.target.previousSibling;
}
}
target.focus();
}
}
hideElementWheel() {
// This is somehow the only option to trigger the showElementWheel
this.setState({ test: false });
}
render() {
return (
<div
className="element-add"
style={{ opacity: this.props.invisible ? 0 : 1 }}
onClick={() => this.setState(prevSate => ({ showElementWheel: !prevSate.showElementWheel }))}
>
<PlusIcon className="element-add__icon" />
{this.state.showElementWheel && (
<React.Fragment>
<div className="element-add__wheel">
<button
autoFocus
className="element-add__circle"
onClick={this.handleAddCardClick.bind(this)}
onKeyDown={this.handleTabPress.bind(this)}
title="New element"
>
<ViewModuleIcon className="element-add__element-icon" />
</button>
<button
className="element-add__circle"
onClick={this.handleAddKnowledgeClick.bind(this)}
onKeyDown={this.handleTabPress.bind(this)}
title="New knowledge-element"
>
<FileIcon className="element-add__element-icon" />
</button>
</div>
<div
className="element-add__close-layer"
onClick={() => {
this.hideElementWheel();
}}
/>
</React.Fragment>
)}
</div>
);
}
}
By writing onClick={this.setState({showStuff: false})} you are actually calling setState as soon as your button is rendered.
You want to give a function reference to onClick, not call it immediately on render.
<button onClick={() => this.setState({showStuff: false})} />
If your button is inside another element with a click listener that you don't want to run on the same click, you must make sure that the click event doesn't propagate to the parent.
<button
onClick={(event) => {
event.stopPropagation();
this.setState({showStuff: false});
}}
/>
Actually the onClick prop expects a function, you are already providing a function call, so the setState will be called each time the component is rendered, not when clicked.
Try this:
<button onClick={() => this.setState({showStuff: false})} />
Should behave as you expect :)
Works perfectly fine when I update showStuff true (see updated code below.). My guess is the code that is supposed to set showStuff: true is not working. I also added some text in the button.
import React from 'react'
import ReactDOM from 'react-dom'
class Componenent extends React.Component {
constructor(props) {
super(props);
this.state = {showStuff: true};
}
render() {
return(
<div>
{this.state.showStuff && (
<button onClick={() => this.setState({showStuff: false})} > This is a button</button>
)}
</div>
);
}
}
ReactDOM.render(<Componenent />,
document.getElementById('root')
);
Before clicking
After clicking

React Bootstrap Dropdown Button OnSelect

I am passing the option values into a series of Dropdown buttons, each of which is in a child component from a data array.
When an option is chosen in one of the buttons I am updating the state in the parent component with the result of onSelect. This is all working fine...
//parent component
sourceSelected = (event) => {
this.setState({
sourceSelected: event
});
...
<ButtonToolbar>
{MEDIUM.map((medium) =>
<Medium key={medium.medium_name} medium={medium} onSelectedValue{this.sourceSelected } />
)};
</ButtonToolbar>
//child component
<DropdownButton title={props.medium.medium_name} id="source-dropdown" onSelect={props.onSelectedValue}>
{props.medium.source.map((option, index) =>
<MenuItem key={index} eventKey={option}> {option} </MenuItem>)}
</DropdownButton>
However, I would also like to store in the state (mediumSelected=???) the name of the button from which the option was selected.
Is there anyway to get OnSelect to pass this back or should I do something else?
OK, I answered this using... https://reactjs.org/docs/handling-events.html passing arguments to event handlers.
The code is:
//parent component
sourceSelected = ( medium_name, event) => {
this.setState({
sourceSelected: event,
mediumSelected: medium_name
});
}
...
<div className='test'>
<ButtonToolbar>
{MEDIUM.map((medium) =>
<Medium key={medium.medium_name} medium={medium} onSelectedValue={this.sourceSelected.bind(this, medium.medium_name) } />
)};
</ButtonToolbar>
You can take advantage of Javascript events and this. Basically, pass the event to the function that will be using the button name, like this
<button name="btn" onClick={e => this.buttonName(e.target.name)}>
You will also need to bind this in your constructor()
Example code:
constructor(props) {
super(props);
// Bind this so you can use it below
this.buttonName = this.buttonName.bind(this);
}
buttonName(e) {
console.log(e);
}
render() {
return (
<div>
// Pass the name of the button to the function
<button name="btn" onClick={e => this.buttonName(e.target.name)}>
Button
</button>
</div>
);
}
I also threw a quick example on https://codesandbox.io/s/lrwqr303vz. Don't mind the file names.

ReactJS - button onClick gets called during render

I have a form with type="range". Now I would like to add 3 buttons that change the same value that the form does. For some reason, the buttons onClick event seems to get called repeatedly upon calling the render function.
This is my component:
class Slider extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleButton = this.handleButton.bind(this);
}
handleChange() {
this.props.onSetCountdown(parseInt(this.refs.seconds.value, 10));
}
handleButton(value) {
this.props.onSetCountdown(parseInt(value, 10));
}
render() {
return(
<div>
<form className={styles.ttSlider} ref="form">
<input max="480" min="60" name="slider" onChange={this.handleChange} ref="seconds" type="range" value={this.props.totalSeconds}/>
<button onClick={this.handleButton(60)}>1min</button>
<button onClick={this.handleButton(180)}>3min</button>
<button onClick={this.handleButton(300)}>5min</button>
</form>
</div>
)
}
}
Slider.propTypes = {
totalSeconds: React.PropTypes.number.isRequired,
onSetCountdown: React.PropTypes.func.isRequired
};
And this is from the parent component:
handleSetCountdown(seconds) {
this.setState({
count: seconds
});
}
From the parent component render:
<Slider totalSeconds={count} onSetCountdown={this.handleSetCountdown}/>
This is the error that I get:
Warning: setState(...): Cannot update during an existing state
transition (such as within render or another component's
constructor). Render methods should be a pure function of props and
state; constructor side-effects are an anti-pattern, but can be moved
to componentWillMount.
To me this looks like the buttons onClick gets called while the component is still rendering. What am I doing wrong?
It's because instead of passing the function to the event onClick, you're calling the function directly.
Try doing it this way:
<button onClick={() => { this.handleButton(60)}}>1min</button>
<button onClick={() => { this.handleButton(180)}}>3min</button>
<button onClick={() => { this.handleButton(300)}}>5min</button>
Found the answer here: React onClick function fires on render
Hope it helps!
If you dont want to use anon functions for any reason, the second method is to use bind directly at render function. Then you can delete lines at your constructor :)
<button onClick={this.handleButton.bind(this, 60)}>1min</button>

Categories

Resources