React+TypeScript项目中使用FileReader读取文件无输出问题求解
问题排查&修复方案
- 第一个核心排查点:先确认
isTaxonomyDefaultName的取值是否一直为true
你的import csv按钮的onClick逻辑是isTaxonomyDefaultName ? undefined : () => importFile(),如果这个状态值始终为true,按钮点击事件直接被禁用,不会触发文件选择弹窗,自然没有后续的console输出。同时你给Style.MandatoryOption传递了isTaxonomyDefaultNameprop,大概率你的样式文件中对该prop为true的场景设置了pointer-events: none等禁用点击的样式,进一步阻断了点击行为。 - 第二个排查点:如果可以正常弹出文件选择框,选文件后无输出:
- 重复选择同一个文件时,input的value未清空会导致onChange事件不触发,需要在文件读取完成后手动清空input value
- 你当前读取文件用的是
readAsDataURL,如果是读取csv文本内容,应该替换为readAsText方法
- 第三个TypeScript类型优化:不要用any声明事件类型,改为正确的
React.ChangeEvent<HTMLInputElement>类型
修复后参考代码
import { useRecoilValue } from 'recoil'; import { useState, ChangeEvent } from 'react'; import { taxonomySelectorName } from '../../../../../state/header.state'; import { TAXONOMY_SELECTOR, HEADER_TESTS } from '../../../../../constants/header.constants'; import useMandatoryOptionsServices from '../../../../../services/mandatoryOptions.services'; import { options } from '../../../../../constants/mandatoryOptions.constants'; import { IOption } from '../../../../../types/mandatoryOptions/mandatoryOptions.types'; import * as Style from './mandatoryOption.styles'; const MandatoryOptions = () => { const isTaxonomyDefaultName = useRecoilValue(taxonomySelectorName) === TAXONOMY_SELECTOR.PLEASE_SELECT_TAXONOMY; const { setModalAction, handelMandatoryOptionActions } = useMandatoryOptionsServices(); const [nameAndContent, setNameAndContent] = useState({ name: '', content: '' }); const handleClick = (type: string) => { handelMandatoryOptionActions(); setModalAction(type); }; const importFile = () => { document.getElementById<HTMLInputElement>('csv-upload-input')?.click(); }; const handleChangeFile = (e: ChangeEvent<HTMLInputElement>) => { console.log('文件选择事件触发', e); const files = e.target.files; if (!files || files.length === 0) return; console.log('选中的文件列表', files); const reader = new FileReader(); reader.onload = (r) => { console.log('文件读取完成', r.target?.result); // 保存文件名和内容 setNameAndContent({ name: files[0].name, content: r.target?.result as string }); // 清空input value,允许重复选择同一个文件 e.target.value = ''; }; // 读取csv文本用readAsText,需要base64再换回readAsDataURL reader.readAsText(files[0]); }; return ( <> <Style.Hr /> <Style.MandatoryOptionsContainer data-testid={HEADER_TESTS.MANDATORY_OPTIONS}> {options.map((option: IOption, index) => ( <Style.MandatoryOption onClick={isTaxonomyDefaultName ? undefined : () => handleClick(option.functionType)} key={index} isTaxonomyDefaultName={isTaxonomyDefaultName} data-testid={option.dataTestId} > {option.content} </Style.MandatoryOption> ))} <Style.MandatoryOption onClick={isTaxonomyDefaultName ? undefined : importFile} key={'import csv'} isTaxonomyDefaultName={isTaxonomyDefaultName} data-testid={'import csv'} > import csv </Style.MandatoryOption> {/* 建议修改id为语义化命名,避免和其他元素id冲突 */} <input type="file" id="csv-upload-input" accept=".csv" onChange={handleChangeFile} style={{ display: 'none' }} /> </Style.MandatoryOptionsContainer> </> ); }; export default MandatoryOptions;
额外优化点
- 给file input添加
accept=".csv"限制仅可选择csv文件,避免用户上传其他格式文件 - 修改input id为语义化的
csv-upload-input,避免和页面其他用数字命名的id冲突 - 添加了文件非空判断,避免空文件时调用FileReader报错
内容的提问来源于stack exchange,提问作者idan
相关产品推荐
相关产品推荐

