繁体   English   中英

按下 Escape 按钮后,如何在 React 中运行 function?

[英]How to run a function in React when the Escape button has been pressed?

该组件的整个想法是,第一次按下Escape键时,state 中的值confirm更改为true以验证用户确实想要执行secPress() function 并在 5 秒内再次按下Escape键运行secPress() function。

不幸的是,组件中的secPress() function 从未运行过。

如何让 function 在第二次按键后运行?

import React, { useState, useEffect, useCallback } from "react";

export function useKeypress(key, action) {
  useEffect(() => {
    function onKeyup(e) {
      if (e.key === key) action();
    }
    window.addEventListener("keyup", onKeyup);
    return () => window.removeEventListener("keyup", onKeyup);
  }, []);
}

const App = () => {
  const [confirm, setConfirm] = useState(false);

  // this function never run
  const secPress = () => {
    console.log("Double escape pressed");
  };

  const _confirm = useCallback(() => {
    setConfirm((prev) => !prev);
    console.log(confirm); // <-- always show false
    if (confirm) {
      secPress();
    }
  }, [confirm]);

  useKeypress("Escape", _confirm);

  useEffect(() => {
    const d = setTimeout(() => {
      setConfirm(false);
    }, 5000);
    return () => {
      clearTimeout(d);
    };
  }, [confirm]);

  return <>{confirm ? "true" : "false"}</>;
};

export default App;

反应版本:17.0.2

在您的情况下,这是因为您将一个空的依赖项数组传递给 useKeypress function 中的 useEffect; 这样,事件侦听器始终具有相同的回调。

最简单的更改是传递依赖项,例如:

import React, { useState, useEffect, useCallback } from "react";

export function useKeypress(key, action, deps) {
  useEffect(() => {
    function onKeyup(e) {
      if (e.key === key) action();
    }
    window.addEventListener("keyup", onKeyup);
    return () => window.removeEventListener("keyup", onKeyup);
  }, deps);
}

const App = () => {
  const [confirm, setConfirm] = useState(false);

  // this function never run
  const secPress = () => {
    console.log("Double escape pressed");
  };

  const _confirm = useCallback(() => {
    setConfirm(prev => !prev);
    console.log(confirm); // <-- always show false
    if (confirm) {
      secPress();
    }
  }, [confirm]);

  useKeypress("Escape", _confirm, [confirm]);

  useEffect(() => {
    const d = setTimeout(() => {
      setConfirm(false);
    }, 5000);
    return () => {
      clearTimeout(d);
    };
  }, [confirm]);

  return <>{confirm ? "true" : "false"}</>;
};

export default App;

前面的答案不正确,你不应该在事件监听器效果中添加 [confirm]

工作示例:

https://codesandbox.io/s/00rxv

  const [stage, setStage] = useState("initial");

  const secPress = () => {
    console.log("Double escape pressed");
  };

  const keydown = (e) => {
    if (e.key === "Escape") {
      setStage((current) => (current === "initial" ? "confirm" : "success"));
    }
  };

  useEffect(() => {
    window.addEventListener("keydown", keydown);

    return () => window.removeEventListener("keydown", keydown);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (stage === "success") {
      secPress();
    }
    if (stage !== "confirm") {
      return;
    }

    const d = setTimeout(() => {
      setStage("initial");
    }, 2000);
    return () => {
      clearTimeout(d);
    };
  }, [stage]);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM