React Native自定义ActivityIndicator组件:实现延迟显示与防误触发
修复React Native延迟加载指示器的页面跳转后仍显示问题
我用React Native的ActivityIndicator做了一个由布尔状态控制的自定义加载组件,想加个延迟显示功能——只有API调用耗时超过1秒才显示加载器,要是在1秒内完成就不显示。但现在有问题:就算跳转到其他页面,定时器结束后加载器还是会弹出来。
原代码
import { FC, useEffect, useState } from 'react'; import { View, ActivityIndicator, StyleSheet, Modal } from 'react-native'; import { globalPalette } from '../../../themes'; interface Props { visible: boolean; } export const LoadingSpinner: FC<Props> = ({ visible }) => { const [realVisible, setRealVisible] = useState(visible); useEffect(() => { if (visible) { // wait for 1s before showing the spinner setTimeout(() => { if (visible) { setRealVisible(true); } }, 1000); } else { setRealVisible(false); } }, [visible]); return ( <> {realVisible ? ( <Modal animationType="fade" transparent={true} visible={realVisible}> <View style={styles.loaderContainer}> <ActivityIndicator size="large" color={globalPalette.primary} /> </View> </Modal> ) : ( <></> )} </> ); }; const styles = StyleSheet.create({ loaderContainer: { position: 'absolute', top: '40%', left: '25%', backgroundColor: globalPalette.white, justifyContent: 'center', width: '50%', height: '20%', borderColor: globalPalette.primary, borderWidth: 1, borderRadius: 15, shadowColor: '#000', shadowOffset: { width: 0, height: 8, }, shadowOpacity: 0.46, shadowRadius: 11.14, elevation: 17, }, });
问题分析
核心问题是没有清理定时器:当组件卸载(比如跳转到其他页面)或者visible状态变化时,之前创建的定时器依然在后台运行,到时间后就会执行setRealVisible(true),导致加载器错误显示。另外,定时器回调里的visible是闭包捕获的旧值,即使后续visible变为false,回调里的判断依然会用之前的true。
修复后的代码
import { FC, useEffect, useState } from 'react'; import { View, ActivityIndicator, StyleSheet, Modal } from 'react-native'; import { globalPalette } from '../../../themes'; interface Props { visible: boolean; } export const LoadingSpinner: FC<Props> = ({ visible }) => { const [realVisible, setRealVisible] = useState(false); useEffect(() => { let timerId: NodeJS.Timeout; if (visible) { // 1秒后才显示加载器 timerId = setTimeout(() => { setRealVisible(true); }, 1000); } else { // 立即隐藏,同时清除可能存在的定时器 setRealVisible(false); if (timerId) clearTimeout(timerId); } // 组件卸载或依赖项变化时,清理定时器 return () => { if (timerId) clearTimeout(timerId); }; }, [visible]); return ( <Modal animationType="fade" transparent={true} visible={realVisible}> <View style={styles.loaderContainer}> <ActivityIndicator size="large" color={globalPalette.primary} /> </View> </Modal> ); }; const styles = StyleSheet.create({ loaderContainer: { position: 'absolute', top: '40%', left: '25%', backgroundColor: globalPalette.white, justifyContent: 'center', width: '50%', height: '20%', borderColor: globalPalette.primary, borderWidth: 1, borderRadius: 15, shadowColor: '#000', shadowOffset: { width: 0, height: 8, }, shadowOpacity: 0.46, shadowRadius: 11.14, elevation: 17, }, });
关键修复点
- 清理定时器:每次
useEffect执行时保存定时器ID,在组件卸载或visible变化时,通过返回的清理函数清除上一个定时器,避免旧定时器继续执行。 - 优化初始状态:把
realVisible初始值设为false,符合延迟显示的默认逻辑。 - 简化渲染:直接利用Modal的
visible属性控制显示,去掉冗余的条件渲染空组件。
内容的提问来源于stack exchange,提问作者Zcehtro
相关产品推荐
相关产品推荐

