[英]React: trigger onChange on checkbox input when changing checked state programmatically?
I have a ref to an <input type="checkbox"/>
element, and when I programmatically set checked=false
on the element, the element's onChange
callback does not get called.我有一个
<input type="checkbox"/>
元素的引用,当我以编程方式在元素上设置checked=false
时,不会调用元素的onChange
回调。
I tried using ref.dispatchEvent(new Event('input'))
and ref.dispatchEvent(new Event('change'))
and neither caused the React onChange
callback to get executed.我尝试使用
ref.dispatchEvent(new Event('input'))
和ref.dispatchEvent(new Event('change'))
并且都没有导致 React onChange
回调被执行。
All the questions and answers I could find on StackOverflow about this have to do with <input type="text"/>
elements, none dealing with changing the checked
property programmatically on an <input type="checkbox"/>
element and its onChange
handler not being invoked.我可以在 StackOverflow 上找到的所有关于此的问题和答案都与
<input type="text"/>
元素有关,没有涉及以编程方式在<input type="checkbox"/>
元素及其onChange
上更改checked
的属性处理程序未被调用。
Here's a CodePen that demonstrates the issue:这是一个演示该问题的 CodePen:
https://codepen.io/dossy/pen/QWKVNzZ/left/?editors=0011 https://codepen.io/dossy/pen/QWKVNzZ/left/?editors=0011
You can check and uncheck the checkbox, and the <div>Checked!</div>
will appear and disappear as expected.您可以选中和取消选中复选框,
<div>Checked!</div>
将按预期出现和消失。 However, clicking the <button>Reset</button>
will uncheck the checkbox if it's checked, but since the input
's onChange
handler isn't being executed, the div
isn't being hidden as it should be.但是,单击
<button>Reset</button>
将取消选中复选框(如果已选中),但由于未执行input
的onChange
处理程序,因此div
并未按应有的方式隐藏。
... ...
Yes, I know that I could do this as a Controlled Component but that's not the point: I have a use case where using refs is required so I must implement this as an Uncontrolled Component , and getting the onChange
handler to execute when the DOM element changes is the problem I need to solve.是的,我知道我可以将其作为受控组件来执行,但这不是重点:我有一个需要使用 refs 的用例,因此我必须将其实现为不受控制的 Component ,并在 DOM 元素时执行
onChange
处理程序变化是我需要解决的问题。
Thanks!谢谢!
It's better to do things the "react way".最好以“反应方式”做事。
That means, instead of manipulating dom elements with imperative code (if you're using refs, you're using imperative code), do it declaratively with state/props:这意味着,不要使用命令式代码操作 dom 元素(如果您使用 refs,则使用命令式代码),而是使用 state/props 以声明方式进行操作:
function App() {
const [checked,setChecked] = React.useState(false);
return (
<div className="h-screen flex bg-white text-gray-900 justify-center items-center">
<div className="flex items-start w-64">
<div className="flex items-center gap-4">
<button
className="inline-flex items-center px-4 py-2 border border-gray-500 rounded-md"
onClick={() => setChecked(false)}
>
Reset
</button>
<div>Checkbox:</div>
<input
type="checkbox"
checked={checked}
onChange={() => setChecked(!checked)}
className="h-4 w-4 border-gray-300 rounded"
/>
<div className={checked ? '' : 'hidden'}>
Checked!
</div>
</div>
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
Here's a link to the updated pen: https://codepen.io/zuze-lab/pen/QWKVEbY?editors=0011这是更新笔的链接: https://codepen.io/zuze-lab/pen/QWKVEbY?editors=0011
EDIT: I want to be really clear, ref's aren't bad, not at all.编辑:我想非常清楚,裁判还不错,一点也不。 Lots of react libraries expose refs because imperative code makes sense for those libraries APIs.
许多 React 库都暴露了 refs,因为命令式代码对这些库 API 有意义。 When using refs to add event listeners, or imperatively manipulate elements, you're doing things wrong and you need to back up.
当使用 refs 添加事件侦听器或命令式操作元素时,您做错了事,您需要备份。
Here is the working code.这是工作代码。 working link https://codesandbox.io/s/blissful-wozniak-cc1sn?file=/src/Test.js:0-1753
工作链接https://codesandbox.io/s/blissful-wozniak-cc1sn?file=/src/Test.js:0-1753
import React, { useEffect, useRef } from "react";
export function Test() {
const ref_input = useRef(null);
const ref_text = useRef(null);
useEffect(() => {
ref_input.current.addEventListener("change", function (event) {
alert(event.target.checked);
});
}, []);
function triggerEvent(element, eventName) {
var event = document.createEvent("HTMLEvents");
event.initEvent(eventName, false, true);
element.dispatchEvent(event);
}
return (
<div className="h-screen flex bg-white text-gray-900 justify-center items-center">
<div className="flex items-start w-64">
<div className="flex items-center gap-4">
<button
className="inline-flex items-center px-4 py-2 border border-gray-500 rounded-md"
onClick={() => {
ref_input.current.checked = false;
triggerEvent(ref_input.current, "change");
//ref_input.dispatchEvent(new Event("input"));
//ref_input.current.dispatchEvent(new Event("onChange"));
}}
>
Reset
</button>
<div>Checkbox:</div>
<input
ref={ref_input}
type="checkbox"
className="h-4 w-4 border-gray-300 rounded"
// onChange={(e) => {
// console.log("onChange called", e.target.checked);
// e.target.checked
// ? ref_text.current.classList.remove("hidden")
// : ref_text.current.classList.add("hidden");
// }}
/>
<div ref={ref_text} className="hidden">
Checked!
</div>
</div>
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.