Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 不接受输入时对更改作出反应_Reactjs_Mouseevent_React Hooks - Fatal编程技术网

Reactjs 不接受输入时对更改作出反应

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

我有一个奇怪的bug,它只在某些时候发生——onChange触发,但不会改变值。然后,如果我用onChange函数在输入框外单击,然后在输入框内单击,onChange函数开始工作

onChange函数如下所示:

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}
)来覆盖它的一个属性