【问题标题】:How to display uploaded and uploading files using react and typescript?如何使用 react 和 typescript 显示上传和上传的文件?
【发布时间】: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


【解决方案1】:

文件上传完成后,上传队列中的文件一秒钟不显示。

那是因为您在uploadDone 时将isUploading 设置为false

  setIsUploading(false);
  setUploadProgress(0);

但只有当isUploading 为真时,您才会显示队列中的文件。

{isUploading && files && files.map(...)}

因此,这可以防止文件在 uploadDonestartNextFileUpload 持续时间之间呈现。 因此,您可以在渲染时删除isUploading 条件,如下所示:

{files && files.map(...)}

【讨论】:

  • 非常感谢您的回答。它拯救了我的一天 :) 我已经为此工作了将近 4 个小时。所以在我的代码中,isuploading 状态可以完全去掉吗?
  • @someuser2491 没问题。是的,我想是的,因为您的代码中的isuploadingfiles != nullif(files) 是等价的。快乐编码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-11
  • 1970-01-01
  • 1970-01-01
  • 2020-03-22
  • 1970-01-01
  • 2018-01-19
  • 2021-07-12
相关资源
最近更新 更多