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

Next.js单输入框上传图/视频后预览组件判断失效问题求助

问题:图片/视频上传预览判断失效,始终显示视频组件

实现支持图片和视频上传的输入框后,上传功能正常,但预览时无论上传图片还是视频,都会触发视频组件渲染,完全不走图片分支。尝试用useState存储file_type也未解决问题。

错误原因

  • 变量作用域与渲染机制冲突:组件顶部声明的var file_type是函数级变量,React组件每次状态更新都会重新执行整个组件函数,该变量会被重置为undefined。渲染阶段判断file_type === "image"时,实际是undefined === "image",永远为false,因此始终走视频分支。
  • useState用法错误(若曾尝试):若之前仅声明useState但未在onFileChange中正确更新状态,或渲染时仍使用原变量而非state值,同样会导致判断失效。

修复方案

通过useState持久化存储文件类型,确保组件渲染时能获取到正确值,同时添加Blob URL清理逻辑避免内存泄漏。

修复后的完整代码

import React, { useState, useEffect } from 'react';
import { CgAttachment } from "react-icons/cg";
import { MdDeleteForever } from 'react-icons/md';

const ChatFooter = () => {
  const [attachmentPreview, setAttachmentPreview] = useState(null);
  const [attachment, setAttachment] = useState(null);
  // 新增state存储文件类型
  const [fileType, setFileType] = useState(null);

  // 清理Blob URL,避免内存泄漏
  useEffect(() => {
    return () => {
      if (attachmentPreview) {
        URL.revokeObjectURL(attachmentPreview);
      }
    };
  }, [attachmentPreview]);

  const onFileChange = (e) => {
    const file = e.target.files[0];
    if (!file) return;

    const file_name = file.name;
    let file_type = file.type.toLowerCase();
    // 提取文件类型前缀(image/video)
    file_type = file_type.substr(0, file_type.indexOf("/"));
    
    const blobUrl = URL.createObjectURL(file);
    
    setAttachment(file);
    setAttachmentPreview(blobUrl);
    // 更新文件类型state
    setFileType(file_type);
    
    e.target.value = "";
  }  

  return (
    <>
      {attachmentPreview && (
        <div className='absolute w-[100px] h-[100px] bottom-16 left-0 bg-c1 p-2 rounded-md'>
          {/* 使用state中的fileType进行判断 */}
          {fileType === "image" ? (
            <img src={attachmentPreview} alt='Attachment Preview' className='w-full h-full object-cover' />
          ) : (
            <video width="100" height="100" controls className='w-full h-full object-cover'>
              <source src={attachmentPreview} type={attachment?.type} />
            </video>
          )}
          <div 
            className='absolute -right-2 -top-2 cursor-pointer w-6 h-6 rounded-full bg-red-500 flex justify-center items-center'
            onClick={() => {
              setAttachment(null);
              setAttachmentPreview(null);
              setFileType(null);
            }}
          >
            <MdDeleteForever size={14} />
          </div> 
        </div>
      )}
      <div className='shrink-0'>
        <input
          type='file'
          id='fileUploader'
          className='hidden'
          onChange={onFileChange}
          accept='image/*, video/*'
        />
        <label htmlFor='fileUploader'>
          <CgAttachment size={20} />
        </label>
      </div>
    </>
  );
}

export default ChatFooter;

关键修复点

  • 新增const [fileType, setFileType] = useState(null)持久化存储文件类型,确保渲染时能获取最新值
  • 在onFileChange中处理完文件类型后,调用setFileType(file_type)更新状态
  • 渲染阶段使用fileType代替原变量进行分支判断
  • 添加useEffect钩子清理Blob URL,避免内存泄漏
  • 视频组件type属性使用文件原生类型,提升兼容性
  • 给图片和视频添加样式,确保预览内容适配容器尺寸

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 01:32:21