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

如何避免在多处复用的React组件中重复渲染图片?

解决图片复用加载闪烁问题

核心原因

图片虽在首页已加载并被浏览器缓存,但组件复用时仍会出现闪烁:

  • 组件卸载后重新挂载,<img>元素被重新创建,浏览器需重新验证缓存,产生短暂延迟
  • 初始设为display:none的图片未提前加载,切换显示时触发加载流程

解决方案

1. 全局预加载图片

在应用初始化阶段(如入口文件或首页组件)预加载所有目标图片,强制浏览器缓存资源:

// 在App.js或首页组件中添加
useEffect(() => {
  const imageUrls = [maleImageUrl, femaleImageUrl, dogImageUrl];
  imageUrls.forEach(url => {
    const img = new Image();
    img.src = url;
  });
}, []);

2. 保持图片DOM元素持久化

避免用display:none隐藏图片,改用visibility/opacity配合绝对定位,让图片始终存在于DOM中:

// 定义图片显示/隐藏样式逻辑
const getImageStyle = (isVisible) => ({
  visibility: isVisible ? 'visible' : 'hidden',
  opacity: isVisible ? 1 : 0,
  position: 'absolute',
  top: 0,
  left: 0,
  transition: 'opacity 0.3s ease' // 可添加过渡动画优化体验
});

// 修改组件返回结构
return (
  <Box style={{ position: 'relative', width: '100%', height: '82vh' }}>
    <img src={male} className={classes.image} style={getImageStyle(showMale)} />
    <img src={female} className={classes.image} style={getImageStyle(showFemale)} />
    <img src={dog} className={classes.image} style={getImageStyle(currentUser?.userType === 'trainer')} />
  </Box>
);

3. 优化Redux选择器稳定性

用shallowEqual确保useAppSelector返回值引用稳定,避免不必要的组件重渲染:

import { shallowEqual, useAppSelector } from '../../redux-store/hooks';

// 修改选择器调用
const currentUser = useAppSelector((state) => state.auth.currentUser, shallowEqual);

4. 修正代码错误

代码中dog的useMemo依赖了不存在的trainerImageUrl,需改为dogImageUrl:

const dog = useMemo(() => dogImageUrl, []);

完整修改后的组件代码

import React, { useEffect, useState, useMemo, memo } from 'react';
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import { Box } from '@material-ui/core/';
import { shallowEqual, useAppSelector } from '../../redux-store/hooks';

interface Props {
  homePage: boolean;
  loading: boolean;
}

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    image: {
      maxWidth: '100vw',
      marginTop: 'auto',
      backgroundRepeat: 'no-repeat',
      maxHeight: '82vh',
      backgroundSize: 'auto',
      filter: 'grayscale(50%) drop-shadow(12px 12px 12px rgba(128,128,128 ,0.1))',
    },
  })
);

const SplashImages: React.FC<Props> = memo(({ homePage, loading }) => {
  const maleImageUrl = // 你的图片URL
  const femaleImageUrl =  // 你的图片URL
  const dogImageUrl =  // 你的图片URL

  const male = useMemo(() => maleImageUrl, []);
  const female = useMemo(() => femaleImageUrl, []);
  const dog = useMemo(() => dogImageUrl, []);

  const classes = useStyles();
  const currentUser = useAppSelector((state) => state.auth.currentUser, shallowEqual);
  const [isMale, setIsMale] = useState(true);

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      setIsMale(!isMale);
    }, 3000);

    return () => clearTimeout(timeoutId);
  }, [isMale]);

  const showMale = currentUser?.userType !== 'dog' && isMale;
  const showFemale = currentUser?.userType !== 'dog' && !isMale;
  const showDog = currentUser?.userType === 'trainer';

  const getImageStyle = (isVisible) => ({
    visibility: isVisible ? 'visible' : 'hidden',
    opacity: isVisible ? 1 : 0,
    position: 'absolute',
    top: 0,
    left: 0,
    transition: 'opacity 0.3s ease'
  });

  return (
    <Box style={{ position: 'relative', width: '100%', height: '82vh' }}>
      <img src={male} className={classes.image} style={getImageStyle(showMale)} />
      <img src={female} className={classes.image} style={getImageStyle(showFemale)} />
      <img src={dog} className={classes.image} style={getImageStyle(showDog)} />
    </Box>
  );
});

export default SplashImages;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 14:20:33