You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native多屏幕下检测用户闲置实现登出功能求助

React Native 多屏幕场景下的用户闲置检测方案

首先先分析你现有代码的问题:

  • PanResponder未挂载到视图:你创建了PanResponder,但没有将它的panHandlers绑定到任何全屏组件上,导致触摸事件根本无法被捕获。
  • timerRef初始值错误:setTimeout返回的是数字类型的定时器ID,你初始化为false会导致clearTimeout无法正常工作,应该设为null。
  • 超时时间设置不合理:timeForInactivityInSecond设为1000意味着超时时间是1000*1000=1,000,000毫秒(约16.7分钟),如果是测试的话建议设小一点(比如10秒)。
  • 事件监听不全面:只监听onStartShouldSetPanResponderCapture可能漏掉部分交互,比如滑动过程中的事件。

全局闲置检测实现方案(适配多屏幕场景)

要在多屏幕场景下统一检测闲置,最好的方式是在根节点添加全局触摸监听,配合Context管理闲置状态,确保所有屏幕的交互都能触发定时器重置。

步骤1:创建全局IdleProvider

这个Provider会封装定时器逻辑和PanResponder监听,所有子组件都能通过Hook获取状态和重置方法。

import React, { createContext, useContext, useRef, useEffect, useState } from 'react';
import { PanResponder, View } from 'react-native';

const IdleContext = createContext();

export const IdleProvider = ({ children, timeoutSeconds = 600 }) => {
  const timerId = useRef(null);
  const [isIdle, setIsIdle] = useState(false);

  // 重置闲置定时器
  const resetInactivityTimeout = () => {
    setIsIdle(false);
    clearTimeout(timerId.current);
    timerId.current = setTimeout(() => {
      setIsIdle(true);
      // 这里写闲置触发的逻辑,比如登出API调用
      console.log('用户闲置,执行会话登出');
    }, timeoutSeconds * 1000);
  };

  // 初始化和清理定时器
  useEffect(() => {
    resetInactivityTimeout();
    return () => clearTimeout(timerId.current);
  }, [timeoutSeconds]);

  // 捕获所有触摸交互
  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponderCapture: () => {
        resetInactivityTimeout();
        return false; // 不接管触摸事件,仅捕获触发重置
      },
      onMoveShouldSetPanResponderCapture: () => {
        resetInactivityTimeout();
        return false;
      },
    })
  ).current;

  return (
    <IdleContext.Provider value={{ isIdle, resetInactivityTimeout }}>
      {/* 全屏容器绑定PanResponder,捕获所有触摸事件 */}
      <View style={{ flex: 1 }} {...panResponder.panHandlers}>
        {children}
      </View>
    </IdleContext.Provider>
  );
};

// 自定义Hook,方便组件调用
export const useIdle = () => useContext(IdleContext);

步骤2:在根组件中注入Provider

将整个导航容器包裹在IdleProvider中,确保全局生效:

import { NavigationContainer } from '@react-navigation/native';
import { IdleProvider } from './IdleProvider';

export default function App() {
  return (
    {/* 设置闲置超时时间,比如600秒=10分钟 */}
    <IdleProvider timeoutSeconds={600}>
      <NavigationContainer>
        {/* 你的导航栈定义 */}
      </NavigationContainer>
    </IdleProvider>
  );
}

步骤3:监听闲置状态触发登出

创建全局组件监听isIdle状态,一旦触发就执行登出和导航跳转:

import { useIdle } from './IdleProvider';
import { useNavigation, useFocusEffect } from '@react-navigation/native';
import { useCallback } from 'react';

const GlobalIdleHandler = () => {
  const { isIdle, resetInactivityTimeout } = useIdle();
  const navigation = useNavigation();

  // 屏幕切换时重置定时器
  useFocusEffect(
    useCallback(() => {
      resetInactivityTimeout();
    }, [resetInactivityTimeout])
  );

  // 闲置触发时执行登出
  useEffect(() => {
    if (isIdle) {
      // 清除本地存储的token等会话信息
      // AsyncStorage.removeItem('authToken');
      
      // 导航到登录页,重置导航栈
      navigation.reset({
        index: 0,
        routes: [{ name: 'Login' }],
      });
    }
  }, [isIdle, navigation]);

  return null;
};

然后把这个组件加到导航容器里:

<NavigationContainer>
  <GlobalIdleHandler />
  {/* 你的导航栈 */}
</NavigationContainer>

额外补充:处理非触摸交互

如果需要监听键盘输入、按钮点击等非触摸事件,可以在对应的组件中调用resetInactivityTimeout:

import { useIdle } from './IdleProvider';
import { TextInput } from 'react-native';

const ExampleInput = () => {
  const { resetInactivityTimeout } = useIdle();

  return (
    <TextInput
      onFocus={resetInactivityTimeout}
      onChangeText={resetInactivityTimeout}
      placeholder="输入内容..."
    />
  );
};

内容的提问来源于stack exchange,提问作者Sarathi Ashok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 18:23:23