reactjs - 为什么添加输入事件侦听器会破坏反应中的托管输入?
问题描述
我正在尝试编写一个钩子,它接受一个(参考 a)输入元素并监听它的更新。由于它是与渲染分离的,因此在挂钩中,我不能onInput
直接在元素上使用普通道具。
在事件侦听器中更新不相关的状态(使用useState
钩子)时,输入元素会中断,您无法输入它,而是插入符号/焦点更改。
为什么会addEventListener('input', handleInput)
以onInput={handleInput}
这种方式做出不同的反应,以及解决此问题的最佳方法是什么?
这是重现该问题的片段:
const Hello = (props) => {
const inputRef = React.useRef();
const [val, setVal] = React.useState("Can't type here");
const [other, setOther] = React.useState(0);
React.useEffect(() => {
const inputEl = inputRef.current;
const handleInput = (ev) => {
console.log('In handleInput');
setOther(prev => prev + 1)
};
inputEl.addEventListener('input', handleInput);
return () => inputEl.removeEventListener('input', handleInput);
}, []);
return (
<input
ref={inputRef}
value={val}
onChange={ev => setVal(ev.target.value)}
/>
);
}
ReactDOM.render(
<Hello />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
解决方案
您的非 React 事件正在触发状态更改setOther(prev => prev + 1)
,这会导致组件在 React 事件发生之前重新渲染。
我通常会建议尽可能不要使用非 React 事件,如果你需要它们的结果代码来影响状态,绝对是这样。
如果您从 vanilla JS 事件处理程序中删除状态更改,则组件应按预期运行:
const Hello = (props) => {
const inputRef = React.useRef();
const [val, setVal] = React.useState("Can't type here");
const [other, setOther] = React.useState(0);
React.useEffect(() => {
const inputEl = inputRef.current;
const handleInput = (ev) => {
console.log('In handleInput');
};
inputEl.addEventListener('input', handleInput);
return () => inputEl.removeEventListener('input', handleInput);
}, []);
return (
<input
ref={inputRef}
value={val}
onChange={ev => setVal(ev.target.value)}
/>
);
}
ReactDOM.render(
<Hello />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
如果您需要这两个事件,为什么不将它们都附加到 React 事件,就像这样(ReactonChange
监听 input,而不是模糊):
const Hello = (props) => {
const inputRef = React.useRef();
const [val, setVal] = React.useState("Can't type here");
const [other, setOther] = React.useState(0);
return (
<input
ref={inputRef}
value={val}
onChange={ev => {
setVal(ev.target.value)
console.log('In handleInput')
setOther(prev => prev + 1)
}}
/>
);
}
ReactDOM.render(
<Hello />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
推荐阅读
- jquery - jquery非标准字符颜色错误
- nativescript - Nativescript 嵌套的 RadListView 无法在 iOS 13 上呈现
- oracle - 18c PDB 服务未在 lsnrctl stat 或 services 中列出
- c# - LINQ to Entities 解决方法中不支持指定的类型成员“日期”
- android - How to get date from 2020-02-27T15:00:43+0000 format
- python - Blob 存储:连接到模拟器,本地开发失败
- javascript - 尝试使用 CustomJS 加载新图像时查看临时文件的散景
- python - 将大量数据从一个表插入另一个 MySQL Python
- validation - 为什么 Rails 显示验证错误?
- python - 覆盖在使用 python 3.8 但不是 3.7 的 Windows 上运行非常缓慢