React Native 使用递归setTimeout定时重试数据加载的异常排查
问题修复方案
你代码的核心问题出在3个地方:
clearTimeout接收的参数是setTimeout返回的定时器ID,不是回调函数本身,你之前传refresh给 clearTimeout 完全没有清除效果- useEffect 和 refresh 函数里重复创建定时器,online 状态变更后 useEffect 会触发新的定时器创建,导致已经在线了还会重复执行
- useCallback 依赖 online 导致每次状态变更 refresh 实例都会更新,旧定时器里引用的还是老版本的 refresh 逻辑,状态判断会出错
修复后的完整代码
import { useState, useCallback, useEffect, useRef } from 'react'; // 按实际使用的UI库调整引入,这里默认按react-native示例 import { View, Text, Button } from 'react-native'; export default function NetworkRetryPage() { const [online, setOnline] = useState(false); const [loading, setLoading] = useState(false); // 用ref存储定时器ID,跨渲染周期保持引用 const timerRef = useRef(null); const handleChange = () => { setOnline(prev => !prev); }; const refresh = useCallback(async () => { setLoading(true); // 实际场景替换为你的异步数据加载逻辑 // const loadSuccess = await loadData() // setOnline(loadSuccess) if (!online) { console.log('still offline'); timerRef.current = setTimeout(refresh, 10000); } else { setLoading(false); // 正确清除当前定时器 if (timerRef.current) { clearTimeout(timerRef.current); timerRef.current = null; } console.log('back on line'); } }, [online]); useEffect(() => { // 页面挂载后立即执行第一次刷新,符合你要的挂载就运行的需求 refresh(); // 组件卸载时清除定时器,避免内存泄漏 return () => { if (timerRef.current) { clearTimeout(timerRef.current); timerRef.current = null; } }; // 只在挂载时执行一次,不需要额外依赖 }, []); return ( <View> {online ? <Text>Online</Text> : <Text>Offline</Text>} {loading ? <Text>Loading</Text> : <Text>IDLE</Text>} <Button title="切换在线状态" onPress={handleChange} /> </View> ); }
调整说明
- 新增
timerRef存储定时器ID,保证每次都能精准定位到要清除的定时器 - 移除 useEffect 里的定时器创建逻辑,重试逻辑全由 refresh 内部控制,避免重复生成定时器
- 修正 clearTimeout 的传参逻辑,用存储的定时器ID做清除
- 增加组件卸载时的定时器清除逻辑,避免内存泄漏
- handleChange 改成函数式更新 state,避免闭包导致的状态更新错误
内容的提问来源于stack exchange,提问作者Wasteland
相关产品推荐
相关产品推荐

