使用 React Hooks,你将如何编写一个依赖于状态的事件监听器,而不需要在每次状态更改时添加和删除?

Using react hooks, how would you write an event listener dependent on state that does not need to be added and removed every time the state changes?

下面的代码显示了在 React Native 中一个有效但低效的 Android BackHandler 实现,让应用程序在两秒内按两次后退出。这是在应用程序的主要功能组件中使用 React 挂钩实现的。

但是,由于依赖于状态变量 recentlyPressedHardwareBackuseEffect 挂钩将在每次状态更改时进行清理,然后 运行,从而导致 BackHandler 事件侦听器每当按下后退按钮时,就会分离并重新连接。如何在不不断创建和删除的情况下仅设置一次此事件侦听器,同时允许它访问不断变化的组件状态?

const [recentlyPressedHardwareBack, setRecentlyPressedHardwareBack] =
    useState(false);

  useEffect(() => {
    const backHandler = BackHandler.addEventListener(
      'hardwareBackPress',
      () => {
        // Exit app if user pressed the button within last 2 seconds.
        if (recentlyPressedHardwareBack) {
          return false;
        }

        ToastAndroid.show(
          'Press back again to exit the app',
          ToastAndroid.SHORT,
        );

        setRecentlyPressedHardwareBack(true);

        // Toast shows for approx 2 seconds, so this is the valid period for exiting the app.
        setTimeout(() => {
          setRecentlyPressedHardwareBack(false);
        }, 2000);

        // Don't exit yet.
        return true;
      },
    );

    return () => backHandler.remove();
  }, [recentlyPressedHardwareBack]);

您可以为此使用 useRef。

const recentlyPressedHardwareBackRef = useRef(false);
useEffect(() => {
    const backHandler = BackHandler.addEventListener(
      'hardwareBackPress',
      () => {
        // Exit app if user pressed the button within last 2 seconds.
        if (recentlyPressedHardwareBackRef.current) {
          return false;
        }

        ToastAndroid.show(
          'Press back again to exit the app',
          ToastAndroid.SHORT,
        );

        recentlyPressedHardwareBackRef.current = true;

        // Toast shows for approx 2 seconds, so this is the valid period for exiting the app.
        setTimeout(() => {
          recentlyPressedHardwareBackRef.current = false;
        }, 2000);

        // Don't exit yet.
        return true;
      },
    );

    return () => backHandler.remove();
}, [])