admin管理员组文章数量:1327826
I want to handle changes by keyboard differently from changes by mouse clicks. For this purpose I have created following ponent. My problem is, that when I use the arrow keys and space to select the radio button, it uses the onClick method from the parent div element before it uses the onChange method from the input element. What is the reason for this behaviour and how can I handle it correctly?
class Radio extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.onClick = this.onClick.bind(this);
this.state = { checked: false };
}
onChange() {
this.setState({ checked: !this.state.checked });
console.log('onChange');
}
onClick() {
this.onChange();
console.log('onClick');
}
render() {
return (
<div onClick={this.onClick}>
<input
type="radio"
checked={this.state.checked}
onChange={this.onChange}
/>
Click me!
</div>
);
}
}
ReactDOM.render(<Radio />, document.getElementById('root'));
<div id="root"></div>
<script src=".0.2/react.min.js"></script>
<script src=".0.2/react-dom.min.js"></script>
I want to handle changes by keyboard differently from changes by mouse clicks. For this purpose I have created following ponent. My problem is, that when I use the arrow keys and space to select the radio button, it uses the onClick method from the parent div element before it uses the onChange method from the input element. What is the reason for this behaviour and how can I handle it correctly?
class Radio extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.onClick = this.onClick.bind(this);
this.state = { checked: false };
}
onChange() {
this.setState({ checked: !this.state.checked });
console.log('onChange');
}
onClick() {
this.onChange();
console.log('onClick');
}
render() {
return (
<div onClick={this.onClick}>
<input
type="radio"
checked={this.state.checked}
onChange={this.onChange}
/>
Click me!
</div>
);
}
}
ReactDOM.render(<Radio />, document.getElementById('root'));
<div id="root"></div>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.0.2/react-dom.min.js"></script>
Share
Improve this question
edited Jun 2, 2017 at 8:54
asked Jun 2, 2017 at 8:47
user5520186user5520186
3 Answers
Reset to default 4As seen in this issue and this part of the W3C documentation, this seems to be a default browser behavior.
When the user triggers an element with a defined activation behavior in a manner other than clicking it, the default action of the interaction event must be to run synthetic click activation steps on the element.
To work around this, add the following logic in your onClick
handler:
if (e.type === 'click' && e.clientX !== 0 && e.clientY !== 0) {
// This is a real click. Do something here
}
Creds to GitHub user Ro Savage, for pointing this out.
Here's a full demo for you:
class Radio extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.onClick = this.onClick.bind(this);
this.state = { checked: false };
}
onChange() {
this.setState({ checked: !this.state.checked });
console.log('onChange');
}
onClick(e) {
if (e.type === 'click' && e.clientX !== 0 && e.clientY !== 0) {
this.onChange();
console.log('onClick');
} else {
console.log('prevented "onClick" on keypress');
}
}
render() {
return (
<div onClick={this.onClick}>
<input
type="radio"
checked={this.state.checked}
onChange={this.onChange}
/>
Click me!
</div>
);
}
}
ReactDOM.render(<Radio />, document.getElementById('root'));
<div id="root"></div>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.0.2/react-dom.min.js"></script>
You can disable the propagation of the click event:
<input
type="radio"
checked={this.state.checked}
onClick={(e)=>{e.stopPropagation()}}
onChange={this.onChange}
/>
The order of events matters: the click event will fire before the change event.
Because events bubble up, the onClick
-handler of the parent elements will get triggered before the onChange
-handler of the child-element.
To fix your specific issue, you could for example listen to the keydown
-event on the container-div. This event should get triggered before click- or change-events.
class Radio extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.onKeyUp = this.onKeyUp.bind(this);
this.state = { checked: false };
}
onChange() {
this.setState({ checked: !this.state.checked });
console.log('onChange');
}
onKeyUp() {
console.log('onKeyUp');
this.onChange();
}
render() {
return (
<div onKeyUp={this.onKeyUp}>
<input
type="radio"
checked={this.state.checked}
onChange={this.onChange}
/>
Click me!
</div>
);
}
}
ReactDOM.render(<Radio />, document.getElementById('root'));
<div id="root"></div>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.0.2/react-dom.min.js"></script>
本文标签: javascriptReact onChange on radio button fires onClick on parent div elementStack Overflow
版权声明:本文标题:javascript - React onChange on radio button fires onClick on parent div element - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742225794a2436291.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论