Reactjs 不接受输入时对更改作出反应
我有一个奇怪的bug,它只在某些时候发生——onChange触发,但不会改变值。然后,如果我用onChange函数在输入框外单击,然后在输入框内单击,onChange函数开始工作 onChange函数如下所示:Reactjs 不接受输入时对更改作出反应,reactjs,mouseevent,react-hooks,Reactjs,Mouseevent,React Hooks,我有一个奇怪的bug,它只在某些时候发生——onChange触发,但不会改变值。然后,如果我用onChange函数在输入框外单击,然后在输入框内单击,onChange函数开始工作 onChange函数如下所示: const handleBarAmountChange = (event) => { let newWidthAmount = event.target.value / 10; setNewWidth(newWidthAmount); setNewBarAm
const handleBarAmountChange = (event) => {
let newWidthAmount = event.target.value / 10;
setNewWidth(newWidthAmount);
setNewBarAmount(event.target.value);
};
父div正在使用传递到此函数的带有useRef的ref:
import { useEffect, useState } from 'react';
const useMousePosition = (barRef, barInputRef, barContainerRef) => {
const [ mouseIsDown, setMouseIsDown ] = useState(null);
useEffect(() => {
const setMouseDownEvent = (e) => {
if (e.which == 1) {
if (barContainerRef.current.contains(e.target) && !barInputRef.current.contains(e.target)) {
setMouseIsDown(e.clientX);
} else if (!barInputRef.current.contains(e.target)) {
setMouseIsDown(null);
}
}
};
window.addEventListener('mousemove', setMouseDownEvent);
return () => {
window.removeEventListener('mousemove', setMouseDownEvent);
};
}, []);
return { mouseIsDown };
};
onChange是否与eventListener存在冲突
如何解决此问题?React使用了
合成事件
和事件池
,来自:
事件池
事件
已合并。这意味着调用事件回调后,SyntheticEvent
对象将被重用,所有属性都将为空。这是出于性能原因。因此,您不能以异步方式访问事件
您可以对事件调用event.persist()
,或者将值存储在新变量中,并按如下方式使用它:
const handleBarAmountChange = (event) => {
// event.persist();
// Or
const { value } = event.target;
let newWidthAmount = value / 10;
setNewWidth(newWidthAmount);
setNewBarAmount(value);
};
React使用
合成事件
和事件池
,来自:
事件池
事件
已合并。这意味着调用事件回调后,SyntheticEvent
对象将被重用,所有属性都将为空。这是出于性能原因。因此,您不能以异步方式访问事件
您可以对事件调用event.persist()
,或者将值存储在新变量中,并按如下方式使用它:
const handleBarAmountChange = (event) => {
// event.persist();
// Or
const { value } = event.target;
let newWidthAmount = value / 10;
setNewWidth(newWidthAmount);
setNewBarAmount(value);
};
有一些语法错误和缺少钩子依赖项是导致bug的原因。然而,您可以通过一些调整来简化代码 当使用依赖于其他状态的状态时,我建议将其集中到一个对象中,并使用回调函数同步更新它:
setState(prevState=>({…prevState,示例:“newValue”})
。这与This.setState()类似
在基于类的组件中工作。通过使用单个对象并扩展它的属性({…prevState}
),我们可以通过重新定义其中一个属性({…prevState,newWidth:0}
)来覆盖它的一个属性。这种方式确保值彼此同步
下面的示例遵循上述单个对象模式,其中newWidth
、newparamount
和isDragging
是单个对象的属性(state
)。然后,该示例使用setState
同步更新/覆盖值。此外,已删除引用,并允许将该条拖过窗口(如果您不希望这样做,则希望将其限制在barContainerRef
内,如前所述)。该示例还检查当用户左键单击并按住工具栏时是否存在状态。IsDraging
布尔值。释放左键单击后,将禁用拖动
下面是一个工作示例:
组件/Bar/index.js
import React, { useEffect, useState, useCallback } from "react";
import PropTypes from "prop-types";
import "./Bar.css";
function Bar({ barName, barAmount, colour, maxWidth }) {
const [state, setState] = useState({
newWidth: barAmount / 2,
newBarAmount: barAmount,
isDragging: false
});
// manual input changes
const handleBarAmountChange = useCallback(
({ target: { value } }) => {
setState(prevState => ({
...prevState,
newWidth: value / 2,
newBarAmount: value
}));
},
[]
);
// mouse move
const handleMouseMove = useCallback(
({ clientX }) => {
if (state.isDragging) {
setState(prevState => ({
...prevState,
newWidth: clientX > 0 ? clientX / 2 : 0,
newBarAmount: clientX > 0 ? clientX : 0
}));
}
},
[state.isDragging]
);
// mouse left click hold
const handleMouseDown = useCallback(
() => setState(prevState => ({ ...prevState, isDragging: true })),
[]
);
// mouse left click release
const handleMouseUp = useCallback(() => {
if (state.isDragging) {
setState(prevState => ({
...prevState,
isDragging: false
}));
}
}, [state.isDragging]);
useEffect(() => {
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
return () => {
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
};
}, [handleMouseMove, handleMouseUp]);
return (
<div className="barContainer">
<div className="barName">{barName}</div>
<div
style={{ cursor: state.isDragging ? "grabbing" : "pointer" }}
onMouseDown={handleMouseDown}
className="bar"
>
<svg
width={state.newWidth > maxWidth ? maxWidth : state.newWidth}
height="40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
colour={colour}
>
<rect width={state.newWidth} height="40" fill={colour} />
</svg>
</div>
<div className="barAmountUnit">£</div>
<input
className="barAmount"
type="number"
value={state.newBarAmount}
onChange={handleBarAmountChange}
/>
</div>
);
}
// default props (will be overridden if defined)
Bar.defaultProps = {
barAmount: 300,
maxWidth: 600
};
// check that passed in props match patterns below
Bar.propTypes = {
barName: PropTypes.string,
barAmount: PropTypes.number,
colour: PropTypes.string,
maxWidth: PropTypes.number
};
export default Bar;
import React,{useffect,useState,useCallback}来自“React”;
从“道具类型”导入道具类型;
导入“/Bar.css”;
功能条({barName,BARMOUNT,COLOR,MAXDOWTH}){
常量[状态,设置状态]=使用状态({
新宽度:barAmount/2,
新巴拉蒙特:巴拉蒙特,
IsDraging:错误
});
//手动输入更改
const handleparamountchange=useCallback(
({target:{value}})=>{
设置状态(prevState=>({
…国家,
newWidth:value/2,
纽巴拉蒙特:价值
}));
},
[]
);
//鼠标移动
const handleMouseMove=useCallback(
({clientX})=>{
if(state.isDraging){
设置状态(prevState=>({
…国家,
newWidth:clientX>0?clientX/2:0,
NewParamount:clientX>0?clientX:0
}));
}
},
[国家统计局]
);
//鼠标左键单击保持
const handleMouseDown=useCallback(
()=>setState(prevState=>({…prevState,isDraging:true})),
[]
);
//鼠标左键单击释放
const handleMouseUp=useCallback(()=>{
if(state.isDraging){
设置状态(prevState=>({
…国家,
IsDraging:错误
}));
}
},[state.isDragging]);
useffect(()=>{
window.addEventListener(“mousemove”,handleMouseMove);
window.addEventListener(“mouseup”,handleMouseUp);
return()=>{
window.removeEventListener(“mousemove”,handleMouseMove);
window.removeEventListener(“mouseup”,handleMouseUp);
};
},[handleMouseMove,handleMouseUp]);
返回(
{barName}
maxWidth?maxWidth:state.newWidth}
高度=“40”
fill=“无”
xmlns=”http://www.w3.org/2000/svg"
颜色={color}
>
£
);
}
//默认道具(如果已定义,将被覆盖)
Bar.defaultProps={
巴拉蒙特:300,
最大宽度:600
};
//检查传入的道具是否与下面的模式匹配
Bar.propTypes={
barName:PropTypes.string,
barAmount:PropTypes.number,
颜色:PropTypes.string,
maxWidth:PropTypes.number
};
导出默认栏;
有一些语法错误和缺少钩子依赖项是导致错误的原因。但是,您可以通过一些调整来简化代码
当使用依赖于其他状态的状态时,我建议将其集中到一个对象中,并使用回调函数同步更新它:setState(prevState=>({…prevState,示例:“newValue”})
。这与This.setState()类似
在基于类的组件中工作。通过使用单个对象并扩展它的属性({…prevState}
),我们可以通过重新定义其中一个属性({…prevState,newWidth:0}
)来覆盖它的一个属性