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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:45:27