React单选按钮选中后点击上传按钮Replace、Remove函数未触发问题
问题根因
你的代码主要存在3个逻辑错误,导致Replace、Remove操作看起来没有执行:
- 仅Add操作调用了
setFiles更新状态,Replace和Remove操作仅计算了结果,没有更新状态也没有将最新数据回传给父组件 - 状态设计错误:仅用一个
files变量同时存原有业务数据和新上传的Excel数据,上传新文件时直接覆盖了原有数据,导致Replace、Remove的比对逻辑无法命中 - React的
setState是异步执行的,操作完成后直接读files传给父组件,拿到的永远是更新前的旧值
修复步骤
1. 拆分状态区分原有数据和新上传数据
将单一files状态拆分为两个:
existingData:存储原有业务数据uploadedFileData:存储新上传Excel读取到的待处理数据
2. 修正操作函数逻辑
每个操作处理完成后更新状态,返回最新结果直接传给父组件,避免异步state问题
3. 修正Excel多sheet读取逻辑
XLSX.utils.sheet_to_json的第二个参数为配置项,不能直接传第二个sheet,需要分别转换后合并数据
修正后完整代码
import React, { useState } from "react"; import * as XLSX from "xlsx"; import { makeStyles } from '@material-ui/core/styles'; import Radio from '@material-ui/core/Radio'; import RadioGroup from '@material-ui/core/RadioGroup'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormControl from '@material-ui/core/FormControl'; import Button from '@material-ui/core/Button'; const Upload = (props) => { const [value, setValue] = useState(''); const [error, setError] = useState(false); const [helperText, setHelperText] = useState('') // 拆分状态:原有业务数据 const [existingData, setExistingData] = useState([]); // 拆分状态:新上传的Excel数据 const [uploadedFileData, setUploadedFileData] = useState([]); const [fileName, setFileName] = useState([]); const useStyles = makeStyles((theme) => ({ formControl: { margin: theme.spacing(3), }, button: { margin: theme.spacing(1, 1, 0, 0), }, })); const { passData } = props; const classes = useStyles(); const handleRadioChange = (event) => { console.log(event.target.value,'event') setValue(event.target.value); setError(false); }; const handleClick = (event) => { event.preventDefault(); handlingOperation(); } // 添加操作:新数据追加到原有数据后 const addOperation = () => { const newData = [...existingData, ...uploadedFileData] setExistingData(newData) return newData } // 替换操作:同NPI_ID的更新药店名称 const replaceOperation = () => { const results = existingData.map(x => { const el = uploadedFileData.find(y => y.NPI_ID === x.NPI_ID); if (el) return { ...x, PHARMACY_NAME: el.PHARMACY_NAME }; return x; }); setExistingData(results) return results } // 删除操作:移除和新数据同NPI_ID的条目 const removeOperation = () => { const removeFileFilter = existingData.filter(x => !uploadedFileData.some(y => y.NPI_ID === x.NPI_ID)); setExistingData(removeFileFilter) return removeFileFilter } const handlingOperation = () => { console.log(value, 'value'); let latestData = existingData if (value === 'Add') { latestData = addOperation() setHelperText('文件已添加') } else if (value === 'Replace') { latestData = replaceOperation(); setHelperText('文件已替换') } else if (value === 'Remove') { latestData = removeOperation(); setHelperText('文件已删除') } else { setHelperText('请选择一个操作选项。'); setError(true); } // 直接传处理后的最新值,不依赖异步state passData(latestData) } const addFiles = (newfiles) => { newfiles.map((file) => { const filereader = new FileReader(); filereader.readAsArrayBuffer(file); filereader.onload = (e) => { const bufferArray = e.target.result; const wb = XLSX.read(bufferArray, { type: "buffer" }); const wsname = wb.SheetNames[0]; const ws = wb.Sheets[wsname]; let data = XLSX.utils.sheet_to_json(ws); // 如果需要读第二个sheet,取消下方注释 // if(wb.SheetNames.length > 1) { // const ws1 = wb.Sheets[wb.SheetNames[1]]; // const data1 = XLSX.utils.sheet_to_json(ws1); // data = [...data, ...data1] // } // 新上传的数据存到uploadedFileData,不覆盖原有业务数据 setUploadedFileData(data); }; }); }; const inputsHandler = (e) => { const file = [...e.target.files]; addFiles(file); setFileName(file); } return ( <div className="container-fluid"> <FormControl component="fieldset" error={error} className={classes.formControl}> <div className="title"><div>PHARMACY</div></div> <div className="message"> **Message <span className="messageStatus">{helperText}</span> </div> <section className="heading"> <label className="custom-file-input" for="Upload" > <div className="combiner"> <span className="uploadText">Upload file </span> </div> <div className="combiner selectedFile"> {fileName[0] !== undefined ? <span className="fileName">{fileName[0].name}</span> : null } <input type="file" name="file" id="Upload" className="input-field" accept=".csv, .xlsx,.xls,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" onChange={inputsHandler} multiple /> </div> </label> </section> <div className="radioTitle">Upload a file to:</div> <RadioGroup aria-label="quiz" name="quiz" value={value} onChange={handleRadioChange}> <FormControlLabel value="Add" control={<Radio />} label="Add" /> <FormControlLabel value="Replace" control={<Radio />} label="Replace" /> <FormControlLabel value="Remove" control={<Radio />} label="Remove" /> </RadioGroup> <div className="buttonParent"> <Button type="button" variant="contained" color="primary" className={classes.button} onClick={(e) => { handleClick(e) }} > Upload </Button> </div> </FormControl> </div> ); } export default Upload;
如果你的原有业务数据是从父组件传递而来,可以直接替换掉
existingData状态,从props中读取即可。
内容的提问来源于stack exchange,提问作者Rashmi UI
相关产品推荐
相关产品推荐

