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

React拖拽上传PDF报错:Cannot read properties of undefined (reading 'type')

拖拽PDF文件报错"Cannot read properties of undefined (reading 'type')"的解决办法

我需要实现拖拽文件功能,获取文件名并将文件内容转换为Base64格式。但拖拽上传文档时,执行到if(event.dataTransfer.files[0].type !== "application/pdf")代码行时,出现错误:"Cannot read properties of undefined (reading 'type')"。尝试添加文件存在判断后,代码直接跳过判断退出函数,无法处理文件信息。简化后的代码如下:

import React, {useState} from "react";
import {
    Box,
    Button,
    Typography
} from "@material-ui/core";
import data from "./data.json"
import UploadFileIcon from "@mui/icons-material/UploadFile";

const Up = ({}) => {
    const [popUpConfirm, setPopUpConfirm] = useState(false);
    const [selectedFile, setSelectedFile] = useState();
    const [isFilePicked, setIsFilePicked] = useState(false);
    const [isLoading, setIsLoading] = useState(false);

    const handleSubmit = (event) => {
        event.preventDefault();
        setPopUpConfirm(true);
    };

    const changeHandler = (event) => {
        //changeHandler works
    };

    const handleDragOver = (event) => {
        event.preventDefault();
        event.stopPropagation();
    };

    const handleDrop = (event) => {
        event.preventDefault();
        setIsLoading(true);
        if(event.dataTransfer.files[0].type !== "application/pdf") {
            alert("Must be PDF.");
            return;
        }
        if(event.target.files) {
            setSelectedFile(event.dataTransfer.files[0]);
            setIsFilePicked(true);
            data.documentName = event.dataTransfer.files[0].name;
            getBase64(event.dataTransfer.files[0]).then(
                doc => data.document = doc
            );
        }
        setIsLoading(false);
    };

    //extracts the base64 content (removes the metadata at the beginning) and ensures padding is done correctly.
    function getBase64(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => {
                let encoded = reader.result.toString().replace(/^data:(.*,)?/, '');
                if ((encoded.length % 4) > 0) {
                    encoded += '='.repeat(4 - (encoded.length % 4));
                }
                resolve(encoded);
            };
            reader.onerror = error => reject(error);
        });
    }

    return (
        <>
            <form onSubmit={handleSubmit}>
                <Box onDragOver={handleDragOver} onDrop={handleDrop}>
                    <Box>
                        <Button >
                            {" "}
                            <UploadFileIcon/> Choose a document
                            <input type="file" name="file" onChange={changeHandler} hidden/>
                        </Button>
                        <Typography>Or drop your document here</Typography>
                        {isFilePicked ?
                            <Typography>
                                {selectedFile.name}
                            </Typography>
                            : null}
                    </Box>
                </Box>
                <Box>
                    <Button type="submit">
                        UPLOAD
                    </Button>
                </Box>
            </form>
            <UploadFile open={popUpConfirm} setOpen={setPopUpConfirm} data={data}/>  
        </>
    );
}

export default Up;

问题根源

  1. 直接访问event.dataTransfer.files[0]未做存在性校验,当拖拽的不是文件(比如纯文本)或未拖拽任何文件时,files[0]会是undefined,读取type属性自然报错。
  2. 文件存在判断逻辑错误:event.target.files是针对文件选择框的逻辑,拖拽场景下应检查event.dataTransfer.files的长度,而非event.target.files,这导致有效文件被错误跳过处理。

修复后的代码

import React, {useState} from "react";
import {
    Box,
    Button,
    Typography
} from "@material-ui/core";
import data from "./data.json"
import UploadFileIcon from "@mui/icons-material/UploadFile";

const Up = ({}) => {
    const [popUpConfirm, setPopUpConfirm] = useState(false);
    const [selectedFile, setSelectedFile] = useState();
    const [isFilePicked, setIsFilePicked] = useState(false);
    const [isLoading, setIsLoading] = useState(false);

    const handleSubmit = (event) => {
        event.preventDefault();
        setPopUpConfirm(true);
    };

    const changeHandler = (event) => {
        //changeHandler works
    };

    const handleDragOver = (event) => {
        event.preventDefault();
        event.stopPropagation();
    };

    const handleDrop = (event) => {
        event.preventDefault();
        setIsLoading(true);
        
        // 先判断是否有拖拽文件
        const files = event.dataTransfer.files;
        if (!files || files.length === 0) {
            alert("请拖拽文件");
            setIsLoading(false);
            return;
        }

        const file = files[0];
        // 校验是否为PDF
        if(file.type !== "application/pdf") {
            alert("必须上传PDF文件");
            setIsLoading(false);
            return;
        }

        // 处理文件逻辑
        setSelectedFile(file);
        setIsFilePicked(true);
        data.documentName = file.name;
        getBase64(file).then(
            doc => data.document = doc
        );
        
        setIsLoading(false);
    };

    //extracts the base64 content (removes the metadata at the beginning) and ensures padding is done correctly.
    function getBase64(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => {
                let encoded = reader.result.toString().replace(/^data:(.*,)?/, '');
                if ((encoded.length % 4) > 0) {
                    encoded += '='.repeat(4 - (encoded.length % 4));
                }
                resolve(encoded);
            };
            reader.onerror = error => reject(error);
        });
    }

    return (
        <>
            <form onSubmit={handleSubmit}>
                <Box onDragOver={handleDragOver} onDrop={handleDrop}>
                    <Box>
                        <Button >
                            {" "}
                            <UploadFileIcon/> 选择文档
                            <input type="file" name="file" onChange={changeHandler} hidden/>
                        </Button>
                        <Typography>或拖拽文档到此处</Typography>
                        {isFilePicked ?
                            <Typography>
                                {selectedFile?.name}
                            </Typography>
                            : null}
                    </Box>
                </Box>
                <Box>
                    <Button type="submit">
                        上传
                    </Button>
                </Box>
            </form>
            <UploadFile open={popUpConfirm} setOpen={setPopUpConfirm} data={data}/>  
        </>
    );
}

export default Up;

修复要点

  • 先获取event.dataTransfer.files,判断是否存在且长度大于0,避免直接访问files[0]导致的报错。
  • 将错误的event.target.files判断替换为正确的文件存在校验逻辑。
  • 渲染文件名时添加可选链selectedFile?.name,防止组件初始渲染或未选择文件时的报错。
  • 所有分支都添加setIsLoading(false),避免加载状态一直停留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 07:12:52