【发布时间】:2020-08-06 10:46:32
【问题描述】:
我想将文件上传到服务器并使用 react 和 typescript 将它们显示在列表中。
我想做什么?
我有两个部分,第一个列表和第二个列表。和一个上传按钮来上传文件,如下图所示。
当用户选择文件并单击上传按钮时,将显示用户已选择的文件,并且一旦开始上传,将显示正在上传的文件的进度条(一次只上传一个文件)。文件上传后,文件将从文件状态中删除,附件状态将从服务器获取上传的文件。
下面是我的代码,
function List() {
const [file, setFile] = React.useState({ name: null });
const [files, setFiles] = React.useState([]);
const [isUploading, setIsUploading] = React.useState(false);
const [uploadProgress, setUploadProgress] = React.useState(0);
const fileRef = React.useRef<HTMLInputElement>(null);
const [getAttachmentUploadUrl] = useLazyQuery(GET_UPLOAD_URL, {
onCompleted: (data: any) => uploadFile(data.getAttachmentUploadUrl),
});
useEffect(() => {
if (files && files[0]) {
if (files[0].size > 10000) {
toast.error('File size limit');
setFiles(files.slice(1));
} else {
setFile(files[0]);
getAttachmentUploadUrl();
}
}
}, [files, setFile, setFiles, getAttachmentUploadUrl]);
const uploadFile = async (data: AttachmentUrlResponse) => {
try {
setIsUploading(true);
await axios.put(data.uploadUrl, file, {
onUploadProgress: (progressEvent: any) =>
setUploadProgress(
Math.round((progressEvent.loaded * 100) / progressEvent.total)
),
});
const input: AttachmentCreateInput = {
uploadId: data.uploadId,
section: activeTab, //activeTab is the variable telling which
// tab has been selected by user first list or second list
filename: file.name,
};
await addAttachement({
variables: { input },
});
await refetchAttachment();
setIsUploading(false);
setUploadProgress(0);
setFile({ name: null });
setFiles(files.slice(1));
} catch (e) {
toast.error('File upload failed');
}
};
const handleFilesDrop = (event: any) => {
const { files } = event.type === 'drop' ? event.dataTransfer : event.target;
if (files && files.length > 0) {
handleUploadedFile(files);
}
};
const handleUploadedFile = async (files: any) => {
setFiles(Object.values(files));
};
const uploadClickHandler = () => {
if (fileRef.current) fileRef.current.click();
};
const handleFileChange = (event: React.SyntheticEvent) => {
event.persist();
event.preventDefault();
const { files } = event.target as HTMLInputElement;
if (files && !isUploading) handleUploadedFile(files);
};
const { data: attachments, refetch: refetchattachments } = useQuery(
LIST_ATTACHMENTS
);
return (
<>
<Container>
<Tab>
<span>First list</span>
</Tab>
<Tab>
<span>Second list</span>
</Tab>
<FileListContainer>
{isUploading && files && //this shows files that is to be
// uploaded yet
files.map((file, index) => (
<span>{file.name}</span>
{index=== 0 && <ProgressBar>}
)
}
{attachments && attachments.data.filter( //this has files
// that is uploaded and retrieved from server
(attachment: Attachment) =>
attachment.section === activeTab
)
.map((attachment,index) => (
<span>{attachment.filename}</span>
)
}
</FileListContainer>
<FileUpload onClick={handleFileChange}/>
</Container>
</>
);
}
上面的代码工作正常。但问题是由于状态文件具有用户选择的初始文件,未上传的文件和附件已上传文件,两者都将显示在 FileListContainer 中,文件列表 UI 中会出现一些闪烁,即当一个文件上传完成其他文件时暂时看不到尚未上传的。
所以我正在考虑重新编码此逻辑以从单个数组读取和显示文件,而不是现在从文件和附件中读取和显示两个。但我不知道该怎么做。我是编程新手,尤其是这类编程新手。
有人可以帮我解决这个问题吗?谢谢。
【问题讨论】:
-
when one file upload done the other files that are yet to be uploaded are not seen for a moment.-> 所以当文件上传完成时,上传队列中的文件(尚未上传的文件)不会显示一秒钟?还是只有上传的文件一秒钟不显示? -
上传队列中的文件(尚未上传的文件)一秒钟不显示。
标签: javascript reactjs typescript