Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/423.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
Javascript 使用Hooks-won';在React中设置单击事件的间隔;不要使用更新的状态值_Javascript_Reactjs_Typescript_State_Setinterval - Fatal编程技术网

Javascript 使用Hooks-won';在React中设置单击事件的间隔;不要使用更新的状态值

Javascript 使用Hooks-won';在React中设置单击事件的间隔;不要使用更新的状态值,javascript,reactjs,typescript,state,setinterval,Javascript,Reactjs,Typescript,State,Setinterval,我试图创建一个过滤器下拉菜单,如果用户没有手动关闭它,并且在1秒后将鼠标移离过滤器,它会隐藏自己 问题是mouseInside布尔状态在间隔内从未更改为false。我相信这是因为react组件得到了重新渲染,但并不完全确定 我不知道如何修复它,也不知道如何错误地使用状态变量和局部变量 我在React with hooks中使用了TypeScript: const Filter: React.FC = () => { const [shown, setShown] = useState&

我试图创建一个过滤器下拉菜单,如果用户没有手动关闭它,并且在1秒后将鼠标移离过滤器,它会隐藏自己

问题是
mouseInside
布尔状态在间隔内从未更改为
false
。我相信这是因为react组件得到了重新渲染,但并不完全确定

我不知道如何修复它,也不知道如何错误地使用状态变量和局部变量

我在React with hooks中使用了TypeScript:

const Filter: React.FC = () => {
  const [shown, setShown] = useState<boolean>(false);
  const [mouseInside, setMouseInside] = useState<boolean>(false);
  
  let interval: NodeJS.Timeout | null = null;

  const handleToggle = () => {
      setShown(!shown);
      
      interval = setInterval(() => {
        console.log(mouseInside);

        // mouseInside is permanently true
        if (!mouseInside && interval) {
           // this never gets triggered
           clearInterval(interval);
           setShown(false);
           console.log("Finished!");
        }
      }, 1000);
    }
  };

  return (
    <div
      style={{ width: 100, height: 100, backgroundColor: "lightgray" }}  
      onClick={handleToggle}
      onMouseEnter={() => setMouseInside(true)}
      onMouseLeave={() => setMouseInside(false)}
    >
        <p>Click me!</p>
        
        {shown && <div>drop down here...</dv>}
    </div>
    );
};
const过滤器:React.FC=()=>{
常量[显示,设置显示]=使用状态(假);
const[mouseInside,setMouseInside]=useState(false);
let interval:NodeJS.Timeout | null=null;
const handleToggle=()=>{
设置显示(!如图所示);
间隔=设置间隔(()=>{
控制台日志(鼠标侧);
//mouseInside永远是正确的
if(!mouseInside&&interval){
//这永远不会被触发
间隔时间;
设置显示(假);
console.log(“完成!”);
}
}, 1000);
}
};
返回(
setMouseInside(真)}
onMouseLeave={()=>setMouseInside(false)}
>
点击我

{显示并在此处下拉…} ); };
当用户离开过滤框时,我需要mouseInside最终更改为false。肯定会触发
onMouseLeave
事件,但我认为这是导致问题的原因

也许我需要使用
useffect
?我不知道如何将其与
setInterval

一起使用的最佳方法。为了“订阅”回调函数以更改状态,您完全可以使用
useffect
挂钩:

函数自动调用ThestMouseOutside(){
设置超时(()=>{
如果(鼠标侧){
setMouseInside(假);
}
}, 1000);
}
useEffect(自动在鼠标外[mouseInside]);
useffect
的第二个参数订阅
automaticallySetMouseOutside
,以便在更改
mouseInside
时被调用

虽然此代码旨在举例说明此钩子的使用,它并不准确-因为它可以在用户还在里面时关闭菜单。

如果您想要问题的完整解决方案,请检查此项。

handleToggle
中声明interval action时,它位于自己的范围内,与实际状态没有绑定

const handleInterval = interval => { 
        console.log(mouseInside);
        if (!mouseInside && interval) {
           // this never gets triggered
           clearInterval(interval);
           setShown(false);
           console.log("Finished!");
        }
      }
   
const handleToggle = () => {
      interval = setInterval(() => {
        () => handleInterval(interval),
      }, 1000);
    }
  };

我最终使用了@GalAbra建议的部分内容,但我只想在用户单击切换器时创建间隔,并且仅在菜单打开时:

  const [shown, setShown] = useState<boolean>(false);
  const [mouseInside, setMouseInside] = useState<boolean>(false);

  useEffect(() => {
    let interval: NodeJS.Timeout | null;

    if (shown) {
      interval = setInterval(() => {
        if (!mouseInside && interval) {
          setShown(false);
        }
      }, 500);
    }

    return () => {
      if (interval) clearInterval(interval);
    };
  }, [shown, mouseInside]);

  return (
    <div
      style={{ width: 100, height: 100, backgroundColor: "lightgray" }}  
      onClick={() => setShown(!shown)}
      onMouseEnter={() => setMouseInside(true)}
      onMouseLeave={() => setMouseInside(false)}
    >
        <p>Click me!</p>        
        {shown && <div>drop down here...</dv>}
    </div>
  );
const[显示,设置显示]=使用状态(false);
const[mouseInside,setMouseInside]=useState(false);
useffect(()=>{
let interval:NodeJS.Timeout | null;
如图所示{
间隔=设置间隔(()=>{
if(!mouseInside&&interval){
设置显示(假);
}
}, 500);
}
return()=>{
if(间隔)clearInterval(间隔);
};
},[如图所示,鼠标指针];
返回(
设置显示(!显示)}
onMouseCenter={()=>setMouseInside(true)}
onMouseLeave={()=>setMouseInside(false)}
>
单击我!

{显示并在此处下拉…} );
您在哪里使用
handleToggle
?@GalAbra抱歉。我忘了把它包括在样品里。刚刚加的,谢谢。我让它工作了。我必须像你建议的那样使用effect,并且只有当用户单击下拉列表时才能创建间隔。我不得不稍微修改一下。很高兴听到这个消息!通常情况下,这是比较可取的,因为它会导致性能问题。是的,这是我最关心的问题。我在网上找到的大多数示例都依赖于始终运行的间隔,但我只希望在打开菜单以避免性能问题时运行它。我发布了我的更新版本,因为它确实与您的示例有很大不同,但您给了我正确的方向:)谢谢您的建议。我最终使用useEffect来确保对间隔的引用相同。请注意,由于您在效果中声明了
让间隔
,因此每次输入效果时,您都会声明新的
间隔
。。。考虑使用<代码>让间隔= USERF(NULL)< /代码>外部效果,并分配或清除<代码>间隔。当前< /代码>谢谢。我更新了我的解决方案。我认为使用
interval.current=setInterval
仍然意味着每次输入效果时我都会创建一个新的间隔?我必须在没有useRef的情况下编辑回答案,因为这会导致在每个选项卡上呈现组件时打开多个选项卡的问题。很奇怪。