I think I see what's happening.
You click the button, and it toggles is_checked
, which either checks or unchecks the box. But that ends up triggering an onChange
for the checkbox, which also toggles the state... You've actually coded an infinite loop. Although, since React batches/debounces setState
operations, your code won't lock your page up.
Try this:
2019 Update for hooks API:
import React, { useState } from 'react';
const Component = () => {
const [isChecked, setIsChecked] = useState(true);
return (
<div>
<input
type="checkbox"
onChange={(event) => setIsChecked(event.currentTarget.checked)}
checked={isChecked}
/>
<button onClick={() => setIsChecked(!isChecked)}>
change checkbox state using this button
</button>
</div>
);
};
Original:
var React = require("react");
var Component = React.createClass({
getInitialState: function() {
return {
isChecked: true
};
},
handleCheckboxChange: function(event) {
console.log("checkbox changed!", event);
this.setState({isChecked: event.target.checked});
},
toggleIsChecked: function() {
console.log("toggling isChecked value!");
this.setState({isChecked: !this.state.isChecked});
},
handleButtonClick: function(event) {
console.log("button was pressed!", event);
this.toggleIsChecked();
},
render: function() {
return (
<div>
<input type="checkbox" onChange={this.handleCheckboxChange} checked={this.state.isChecked} />
<button onClick={this.handleButtonClick}>change checkbox state using this button</button>
</div>
);
}
});
module.exports = Component;
Note that you can make this code even cleaner by using React's valueLink (read more here: https://facebook.github.io/react/docs/two-way-binding-helpers.html)
The reason for this behavior has to do with an implementation detail of React - more specifically the way how React normalizes change handling cross browser. With radio and checkbox inputs React uses a click event in place of a change event. When you apply preventDefault
within an attached event handler, this stops the browser from visually updating the radio/checkbox input. There are two possible workarounds:
stopPropagation
alternativelysetTimeout
: setTimeout(x => this.setState(x), 0, {is_checked: !this.state.is_checked});
Preferably you don't use preventDefault
at all, unless it is absolutely necessary.
Look into this React Github issue for further information.
Keep in mind that setState is asynchronous, so:
console.log(event.target.checked);
shall not reflect the changes immediately. My way to handle several checkbox fields:
toggleCheckbox(name, event) {
let obj = {};
obj[name] = !this.state[name];
this.setState(obj);
}
The fields:
<input type="checkbox" name="active" value={this.state.active} checked={this.state.active} onChange={this.toggleCheckbox.bind(this, 'active')} />
<input type="checkbox" name="qtype" value={this.state.qtype} checked={this.state.qtype} onChange={this.toggleCheckbox.bind(this, 'qtype')} />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With