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

React ImageStrip组件状态变更时如何避免图片重新加载?

问题解决:React图片条点击时图片重复加载

问题原因

你的代码里,urls = urlsCallback()会在App组件每次渲染时执行——比如点击图片触发setSelected更新状态的时候,都会重新生成一组带新随机数的图片URL。这就导致所有<img>的src属性被替换,浏览器自然会重新请求新图片。

哪怕urlsCallback用了useCallback缓存,但你每次渲染都调用它生成新数组,urls的引用还是会变,传给ImageStrip后会触发子组件重渲染,且图片URL完全更新。

解决方案:固定图片URL数组

我们要确保图片URL数组只在组件初始化时生成一次,后续渲染不再变化,有两种简单实现方式:

方案1:用useMemo缓存URL数组

把URL数组的生成用useMemo包裹,依赖项设为空数组,确保只执行一次:

import * as React from 'react';
import ImageStrip from './ImageStrip';

function App() {
  const [selected, setSelected] = React.useState('');

  function handleClick(url: string) {
    setSelected(url);
  }

  // 用useMemo缓存,仅组件挂载时生成一次URL数组
  const urls = React.useMemo(() => {
    const randomNumbers = Array.from({ length: 5 }, () =>
      Math.floor(Math.random() * 100)
    ).map((m) => Number(m));

    return randomNumbers.map((m) => `https://picsum.photos/100?random=${m}`);
  }, []);

  return (
    <>
      <div>
        <p>selected url: {selected}</p>
      </div>
      <div>
        <ImageStrip urls={urls} selectedUrl={selected} onClick={handleClick} />
      </div>
    </>
  );
}

export default App;

方案2:在useState中初始化URL数组

直接把URL数组作为useState的初始值,同样只在组件挂载时生成一次:

import * as React from 'react';
import ImageStrip from './ImageStrip';

function App() {
  // 初始化时生成URL数组,后续不再改变
  const [urls] = React.useState(() => {
    const randomNumbers = Array.from({ length: 5 }, () =>
      Math.floor(Math.random() * 100)
    ).map((m) => Number(m));

    return randomNumbers.map((m) => `https://picsum.photos/100?random=${m}`);
  });
  const [selected, setSelected] = React.useState('');

  function handleClick(url: string) {
    setSelected(url);
  }

  return (
    <>
      <div>
        <p>selected url: {selected}</p>
      </div>
      <div>
        <ImageStrip urls={urls} selectedUrl={selected} onClick={handleClick} />
      </div>
    </>
  );
}

export default App;

额外优化:减少ImageStrip不必要渲染

如果ImageStrip组件没做性能优化,哪怕urls不变,selected变化时它还是会重渲染。可以给ImageStrip套个React.memo,避免无意义的重渲染:

// ImageStrip.tsx
import React from 'react';

type Props = {
  urls: string[];
  selectedUrl: string;
  onClick: (url: string) => void;
};

// 用React.memo包裹,仅当props变化时才重渲染
const ImageStrip = React.memo(({ urls, selectedUrl, onClick }: Props) => {
  return (
    <div style={{ display: 'flex', gap: '8px' }}>
      {urls.map((url) => (
        <img
          key={url}
          src={url}
          onClick={() => onClick(url)}
          style={{
            border: selectedUrl === url ? '2px solid blue' : '2px solid transparent',
            borderRadius: '4px'
          }}
          alt="strip item"
        />
      ))}
    </div>
  );
});

export default ImageStrip;

这么处理后,点击图片时只有选中状态变化,图片URL不会重新生成,自然也就不会触发图片重复加载了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 01:35:01