复选框内部状态覆盖道具
checkbox internal state overriding prop
我很惊讶复选框功能不是我所期望的。如果我有一个带有 onClick
的包装器 div,然后单击除复选框之外的任何内容,它会按预期工作。但是,当我单击该复选框时,即使传递下来的 propp 确实更新了,该复选框仍保持相同状态。我的猜测是,在 prop 更改被按下后,复选框正在触发其内部更新事件。
const ToDo = (props) => {
const { title, done, onChange } = props;
const handleChange = (event) => {
event.preventDefault();
if (onChange) {
onChange(!done)
}
}
return (
<div onClick={handleChange}>
<label>
<input type="checkbox" checked={done}/> {title}
</label>
</div>
);
};
我想知道处理这个问题的正确方法是什么?
这是我发现的简单且有效的解决方法。传递不同的键 key={done}
将强制将复选框组件重新呈现为不同的 dom 项目,因此它有效,但似乎应该有更好的方法来做到这一点。我知道在使用文本输入时不需要这样做,因为无论 prop 传递什么值,值都会保持不变。
const ToDo = (props) => {
const { title, done, onChange } = props;
const handleChange = (event) => {
event.preventDefault();
if (onChange) {
onChange(!done)
}
}
return (
<div onClick={handleChange}>
<label>
<input key={done} type="checkbox" checked={done}/> {title}
</label>
</div>
);
};
似乎发生的事情是,当您单击标签时,它会调用复选框的 onChange
函数以及 div 的 onClick
。
解决此问题的一个简单方法是禁用标签上的指针事件,因此仅调用 onClick
(我假设出于某种原因您需要在父对象上使用 onClick
而不是onChange
输入本身)。
可能还有另一种方法可以阻止事件向上传播,但是你必须处理多个处理程序,所以 css 方法似乎很容易解决。
这是一个演示:
class App extends React.Component {
state = {
done: false
}
onCheckDone = (done) => {
this.setState({
done
});
}
render() {
return (
<ToDo
title="hello"
done={this.state.done}
onChange={this.onCheckDone}
/>
);
}
}
const ToDo = (props) => {
const { title, done, onChange } = props;
const handleChange = (event) => {
event.stopPropagation();
if (onChange) {
onChange(!done)
}
}
return (
<div className="clicker" onClick={handleChange}>
<label>
<input type="checkbox" checked={done} /> {title}
</label>
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById('app')
);
.clicker {
border: solid 1px #ccc;
padding: 10px 20px;
}
label {
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
我很惊讶复选框功能不是我所期望的。如果我有一个带有 onClick
的包装器 div,然后单击除复选框之外的任何内容,它会按预期工作。但是,当我单击该复选框时,即使传递下来的 propp 确实更新了,该复选框仍保持相同状态。我的猜测是,在 prop 更改被按下后,复选框正在触发其内部更新事件。
const ToDo = (props) => {
const { title, done, onChange } = props;
const handleChange = (event) => {
event.preventDefault();
if (onChange) {
onChange(!done)
}
}
return (
<div onClick={handleChange}>
<label>
<input type="checkbox" checked={done}/> {title}
</label>
</div>
);
};
我想知道处理这个问题的正确方法是什么?
这是我发现的简单且有效的解决方法。传递不同的键 key={done}
将强制将复选框组件重新呈现为不同的 dom 项目,因此它有效,但似乎应该有更好的方法来做到这一点。我知道在使用文本输入时不需要这样做,因为无论 prop 传递什么值,值都会保持不变。
const ToDo = (props) => {
const { title, done, onChange } = props;
const handleChange = (event) => {
event.preventDefault();
if (onChange) {
onChange(!done)
}
}
return (
<div onClick={handleChange}>
<label>
<input key={done} type="checkbox" checked={done}/> {title}
</label>
</div>
);
};
似乎发生的事情是,当您单击标签时,它会调用复选框的 onChange
函数以及 div 的 onClick
。
解决此问题的一个简单方法是禁用标签上的指针事件,因此仅调用 onClick
(我假设出于某种原因您需要在父对象上使用 onClick
而不是onChange
输入本身)。
可能还有另一种方法可以阻止事件向上传播,但是你必须处理多个处理程序,所以 css 方法似乎很容易解决。
这是一个演示:
class App extends React.Component {
state = {
done: false
}
onCheckDone = (done) => {
this.setState({
done
});
}
render() {
return (
<ToDo
title="hello"
done={this.state.done}
onChange={this.onCheckDone}
/>
);
}
}
const ToDo = (props) => {
const { title, done, onChange } = props;
const handleChange = (event) => {
event.stopPropagation();
if (onChange) {
onChange(!done)
}
}
return (
<div className="clicker" onClick={handleChange}>
<label>
<input type="checkbox" checked={done} /> {title}
</label>
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById('app')
);
.clicker {
border: solid 1px #ccc;
padding: 10px 20px;
}
label {
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>