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

React中<input>选择的图片/视频刷新关闭后失效,如何持久化?

问题原因分析

你用URL.createObjectURL(media)生成的是Blob/File对象的临时内存URL,它本质是浏览器为本地文件在内存中创建的临时引用,有严格的生命周期限制:

  • 这个URL仅在**当前浏览器会话(标签页/窗口未关闭)**内有效,刷新页面、回退路由、关闭浏览器后,浏览器会自动释放对应的内存资源,此时保存的URL就成了无效的空引用。
  • 图片偶尔能在几次刷新后加载,是因为浏览器的临时缓存机制,但缓存没有持久化,一段时间或多次刷新后就会被清理;视频体积更大,浏览器不会对这类临时URL做缓存,所以刷新后直接失效。
解决方案

要实现资源的持久化加载,不能存临时Blob URL,可选择以下两种方式:

方式1:将文件转为Base64编码存储

把本地文件转换成Base64字符串,直接存在localStorage里(注意:localStorage单条数据最大约5MB,大文件不建议用这种方式)。修改代码如下:

修改文件读取逻辑

const loadFileFromDevice = (event: any) => {
  let media = event.target.files[0];
  if (!media) return;

  const reader = new FileReader();
  reader.onload = (e) => {
    const base64Url = e.target?.result as string;
    const isImg = media.type.includes("image");
    
    if (isImg) {
      setImgSrc(base64Url);
      setVideoSrc("");
      localStorage.setItem(IMG_KEY, base64Url);
    } else {
      setImgSrc("");
      setVideoSrc(base64Url);
      localStorage.setItem(VIDEO_KEY, base64Url);
    }
  };
  reader.readAsDataURL(media);
};

初始化和渲染逻辑不变

原来的状态初始化和<img>、<video>渲染代码可直接复用,因为Base64字符串本身就是有效的资源地址。

方式2:上传到服务器存储远程URL

如果文件体积较大(比如超过2-3MB),建议将文件上传到后端服务器,获取服务器返回的远程URL,再把这个URL存在localStorage里。这种方式没有大小限制,且URL是持久有效的。

示例上传逻辑(伪代码)

const loadFileFromDevice = async (event: any) => {
  let media = event.target.files[0];
  if (!media) return;

  // 构建FormData上传
  const formData = new FormData();
  formData.append("media", media);
  
  try {
    const res = await fetch("/api/upload", {
      method: "POST",
      body: formData
    });
    const data = await res.json();
    const remoteUrl = data.url; // 服务器返回的文件URL
    
    const isImg = media.type.includes("image");
    if (isImg) {
      setImgSrc(remoteUrl);
      setVideoSrc("");
      localStorage.setItem(IMG_KEY, remoteUrl);
    } else {
      setImgSrc("");
      setVideoSrc(remoteUrl);
      localStorage.setItem(VIDEO_KEY, remoteUrl);
    }
  } catch (err) {
    console.error("上传失败", err);
  }
};
额外注意事项
  • 用Base64存储时,图片/视频的体积会比原文件大30%左右,要注意localStorage的容量限制。
  • 若曾使用Blob URL,记得在组件卸载时调用URL.revokeObjectURL()释放内存,避免内存泄漏:
useEffect(() => {
  return () => {
    if (imgSrc.startsWith("blob:")) URL.revokeObjectURL(imgSrc);
    if (videoSrc.startsWith("blob:")) URL.revokeObjectURL(videoSrc);
  };
}, [imgSrc, videoSrc]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 21:10:20