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

React应用拉取AWS图片资源时显示全局加载屏实现方案

实现方案(React + Redux + MUI v5 + TypeScript)

核心思路为绕开单张图片绑定加载状态的实现路径,在应用层统一拦截渲染时机:所有跨页面AWS图片预加载完成前仅展示全局加载遮罩,无需修改现有页面的图片样式,适配成本为0。

1. 配置Redux全局加载状态

在Redux中新增资源加载切片,统一存储加载状态、加载进度,支持全局读取,方便后续扩展进度展示等能力。

// src/store/slices/assetLoadSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface AssetLoadState {
  isAllAwsImgsLoaded: boolean;
  loadProgress: number; // 取值范围0-100
}

const initialState: AssetLoadState = {
  isAllAwsImgsLoaded: false,
  loadProgress: 0,
};

const assetLoadSlice = createSlice({
  name: 'assetLoad',
  initialState,
  reducers: {
    setLoadProgress: (state, action: PayloadAction<number>) => {
      state.loadProgress = Math.min(100, Math.max(0, action.payload));
    },
    setAllImgsLoaded: (state) => {
      state.isAllAwsImgsLoaded = true;
      state.loadProgress = 100;
    },
  },
});

export const { setLoadProgress, setAllImgsLoaded } = assetLoadSlice.actions;
export default assetLoadSlice.reducer;

将该reducer加入Redux store配置即可。

2. 统一维护AWS资源清单与预加载逻辑

将7个页面用到的所有AWS Bucket图片链接统一收敛到常量文件维护,避免散落在业务代码中难以统计;同时封装通用预加载方法,单张图片加载失败不阻塞全局流程,防止单图异常导致页面永久处于加载状态。

// src/constants/awsAssets.ts
// 在此处补全7个页面的所有AWS图片链接
export const ALL_AWS_IMAGE_URLS: string[] = [
  'https://[你的AWS Bucket域名]/path/to/img1.png',
  'https://[你的AWS Bucket域名]/path/to/img2.jpg',
];

// 单张图片预加载方法
const preloadSingleImg = (url: string): Promise<void> => {
  return new Promise((resolve) => {
    const img = new Image();
    // 加载成功、失败都触发resolve,避免单图异常阻塞全局
    img.onload = () => resolve();
    img.onerror = () => resolve();
    img.src = url;
  });
};

// 批量预加载,实时回调进度
export const preloadAllAwsImgs = async (onProgressUpdate: (progress: number) => void) => {
  const total = ALL_AWS_IMAGE_URLS.length;
  let loadedCount = 0;

  const loadTasks = ALL_AWS_IMAGE_URLS.map(async (url) => {
    await preloadSingleImg(url);
    loadedCount++;
    onProgressUpdate(Math.round((loadedCount / total) * 100));
  });

  await Promise.all(loadTasks);
};

3. 根组件实现全局渲染拦截

在应用最外层根组件(通常为App.tsx,位于路由组件外层)中,应用初始化即触发全量图片预加载;加载未完成时仅渲染MUI原生组件实现的全屏加载层,加载完成后再渲染实际路由与页面内容。

// src/App.tsx
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Backdrop, CircularProgress, LinearProgress, Box, Typography } from '@mui/material';
import { setLoadProgress, setAllImgsLoaded } from './store/slices/assetLoadSlice';
import { preloadAllAwsImgs } from './constants/awsAssets';
import AppRouter from './router'; // 替换为项目自身的路由配置组件
import type { RootState } from './store';

function App() {
  const dispatch = useDispatch();
  const { isAllAwsImgsLoaded, loadProgress } = useSelector((state: RootState) => state.assetLoad);

  useEffect(() => {
    const startPreload = async () => {
      await preloadAllAwsImgs((progress) => {
        dispatch(setLoadProgress(progress));
      });
      dispatch(setAllImgsLoaded());
    };
    startPreload();
  }, [dispatch]);

  // 资源未加载完成时,仅展示全屏加载层
  if (!isAllAwsImgsLoaded) {
    return (
      <Backdrop 
        open 
        sx={{ 
          zIndex: (theme) => theme.zIndex.drawer + 999, 
          color: '#fff', 
          flexDirection: 'column', 
          gap: 2 
        }}
      >
        <CircularProgress color="inherit" size={60} />
        <Box sx={{ width: '240px' }}>
          <LinearProgress variant="determinate" value={loadProgress} />
        </Box>
        <Typography variant="body2">资源加载中 {loadProgress}%</Typography>
      </Backdrop>
    );
  }

  // 所有资源加载完成后,渲染实际页面与路由
  return <AppRouter />;
}

export default App;

加载层直接使用MUI内置的Backdrop、进度条组件,无需额外编写自定义样式,zIndex设置为最高层级确保完全覆盖页面内容。

可选优化方向

  • 若后续AWS图片资源过多、首屏预加载等待时间过长,可将全量预加载调整为路由级预加载:按路由拆分图片清单,在路由守卫中触发对应路由的图片预加载,核心逻辑与上述方案一致,仅需将预加载触发时机从应用初始化调整为路由跳转前。
  • 可在加载层关闭、页面渲染时增加淡入过渡动画,优化切换体验。
  • 图片资源可拼接版本hash参数,规避浏览器缓存导致的预加载资源与实际渲染资源不一致问题。

内容的提问来源于stack exchange,提问作者Alex Belz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 05:33:23