我刚刚发现一个流浪的
event.preventDefault()
正在破坏我的复选框的 onChange
处理程序:
import { Component } from 'react';
class App extends Component {
constructor(props) {
super(props)
this.state = {
accepted: false
}
}
changeChecked = (event) => {
this.setState((state) => ({
accepted : !state.accepted
}));
event.preventDefault(); // <- this very bad
}
render() {
return (
<input
type="checkbox"
onChange={this.changeChecked}
checked={this.state.accepted}
/>
);
}
}
export default App;
最终的行为是第一次单击时正确更新的状态,但复选框仅在 next 重新渲染时更改为其“选中”外观,例如。第二次点击。
这是为什么呢?受控组件独立于浏览器事件工作不是重点吗?
有人向我解释这一点肯定会减轻我花费数小时来简化复杂用例的痛苦。谢谢!
更新:这是一个快速的 Codepen 示例,演示了奇怪的行为。 我添加了一个“未阻止的复选框”和一个带有阻止的
onClick
事件的复选框作为比较。
请注意,当我单击 different复选框时,具有阻止
onChange
的外观如何将其外观切换为实际状态。
复选框的行为略有不同。您可能知道,
preventDefault()
的典型用例是表单的 onSubmit()
函数,您将在其中执行自己的 AJAX 调用,因此希望阻止默认表单提交。但对于复选框(以及大多数输入),涉及的内容更多。
Per MDN,
checked
属性是“一个布尔属性,指示默认情况下是否选中此复选框(页面加载时)。它不指示当前是否选中此复选框:如果复选框的状态更改后,此内容属性不会反映更改。”有趣的是, checked
属性与是否检查输入状态之间存在脱节。当涉及到 React 时,在每次重新渲染时, checked
属性将反映当前状态,但它仍然只是一个默认值,因为输入是新渲染的,并且自上次状态更改以来未进行操作。
eventListener
为 <input type="checkbox" />
此外,不要太偏离轨道,本机更改复选框输入状态的事件实际上是
click
事件,而不是 change
事件。如果您要弄乱浏览器 js 控制台中的侦听器和复选框输入的值,您会发现可以通过不选中复选框的方式来操作它,但节点的值却另有说明。
基于上述内容,在这种情况下,您不想阻止默认行为,因为
change
事件的默认行为与您想要执行的操作并不冲突(并且由于某种原因阻止它导致问题)。事实上,在 Mozilla 文档示例中,您会注意到他们在更新受控组件上的状态时不使用 preventDefault()
。我希望我能更好地理解到底为什么添加preventDefault()
来更改输入的处理程序会导致这样的问题,但希望这些小花絮能让您更清楚。
尝试将
event.preventDefault()
移动到 this.setState
线上方。