【问题标题】:Return JSZip zip file in React在 React 中返回 JSZip 压缩文件
【发布时间】:2020-08-21 06:02:04
【问题描述】:

我有一个压缩文件的函数,但 atm 它返回一个承诺。我试图实现这一点:jszip stackoverflow 但它仍然返回承诺,未解决。

我对 Promise 不太熟悉,对 jsZIP 也完全不熟悉 - 我如何让这个函数返回压缩文件?

const getZip = (url) => {
        setLoadingStatus('zipping...')
        let zip = new JSZip();
        console.log("TYPOF URL", url, typeof url)
        zip.file("Report", url)
        var promise = null;
        if (JSZip.support.uint8array) {
        promise = zip.generateAsync({type : "uint8array"}).then(content => {
            saveAs(content, "Report.zip");
          });
        } else {
        promise = zip.generateAsync({type : "string"}).then(content => {
            saveAs(content, "Report.zip");
          });
        }
        console.log("TYPEOF PROMISE", promise, typeof promise) //typeof is always promise
        return promise
    }

使用异步等待:

    async function getZip(url){
    setLoadingStatus('zipping...')
    let zip = new JSZip();
    console.log("TYPOF URL", url, typeof url)
    zip.file("Report", url)
    var content = null;
    if (JSZip.support.uint8array) {
        content = await zip.generateAsync({type : "uint8array"}).then(content => {
            saveAs(content, "Report.zip");
          })
    } else {
        content = await zip.generateAsync({type : "string"}).then(content => {
            saveAs(content, "Report.zip");
          })
    }
    return content
}

调用getZip()的函数是:

const createURL = useCallback((node, reportHeight, reportWidth, imgHeight) => {

        domtoimage.toJpeg(node, {width: reportInViewerRef.current.offsetWidth, height: reportInViewerRef.current.scrollHeight})
    .then(function (dataUrl) {
        const pdf = new jsPDF('p', 'px', [reportWidth, imgHeight]);
        setLoadingStatus('pdf created')
        pdf.addImage(dataUrl, 'JPEG', 0, -12, reportWidth, reportHeight );
        setLoadingStatus('image added')
        let fileName = getUniqueFilename()
        let base64pdf = getZip(btoa(fileName, pdf.output()));
        console.log("ZIP FILE =================", base64pdf)
        let storageRef = firebase.storage().ref();
        setLoadingStatus('uploading...')
        let fileLocation = '/pdfs/' + fileName + '.zip'
        let reportPdfRef = storageRef.child(fileLocation);
        reportPdfRef.putString(base64pdf, 'base64').then(function() {
            console.log('Uploaded a data_url string!', reportPdfRef,
            reportPdfRef.getDownloadURL().then(function(url) {
                setLoadingStatus('linking...')
                setTemplateParams({
                    to: sessionData.customerEmail,
                    customers: name, 
                    adviser: adviserFullName,
                    adviserEmail: adviserEmail,
                    adviserAvatar: adviserAvatar,
                    content: url

                }) 
                firebase
                .firestore()
                .collection('sessions')
                .doc(sessionData.id)
                .update({
                    'pdfDownloadURL': url
                }).then(function() {
                    setLoadingStatus('sending email')
                    setSendingEmail(false);
                  });
              }).catch(function(error) {
                switch (error.code) {
                  case 'storage/object-not-found':
                        console.log("FILE DOES NOT EXIST")
                    break;
                  case 'storage/unauthorized':
                        console.log("USER DOES NOT HAVE PERMISSION TO ACCESS THIS FILE")
                    break;

                  case 'storage/canceled':
                        console.log("USER CANCELLED THE UPLOAD")
                    break;
                  case 'storage/unknown':
                        console.log("SERVER ERROR")
                    break;
                }
              })
            )
          });
        })
        .catch(function (error) {
            console.error('oops, something went wrong!', error);
        });
}, [])

【问题讨论】:

  • 最简单的就是使用 async/await。因此,使函数异步,然后执行let content= await zip.generateAsync(...); saveAs(content, "Report.zip"); 之类的操作,然后如果在其他地方需要,您可以返回内容。
  • 你能举个例子吗?抱歉,我对异步等待不太熟悉
  • 你为什么用reactjs标记这个问题?我看不到任何与反应有关的东西。如果您打算在反应组件中使用它并且您不知道如何也请添加相关代码。否则只需删除标签。正如您似乎调用setLoadingStatus 一样,我猜这个函数是使用useState 在组件内部定义的?
  • 这就是一个例子,哈哈,这正是你所需要的。所以在函数定义中你输入async,就像这样:const getZip = async (url)...,然后你在我的第一条评论中使用该代码。 .then 中的“内容”变成了等待调用的返回值,这就是为什么现在不需要 promise 变量,只需将其重命名为 content
  • 你在哪里打电话给getZip?请同时显示周围的组件。

标签: reactjs es6-promise jszip


【解决方案1】:

由于 zip 创建是异步的,因此代码处理也需要异步。做你的 createURL handler async 和 await 里面的 zip:

const createURL = useCallback(async (node, reportHeight, reportWidth, imgHeight) => {
    try {
        const dataUrl = await domtoimage.toJpeg(node, {width: reportInViewerRef.current.offsetWidth, height: reportInViewerRef.current.scrollHeight})
    } catch (error) {
        return console.error('oops, something went wrong!', error);
    }

    // ... you can use dataUrl from here

    let base64pdf = await getZip(btoa(fileName, pdf.output()));

    // ... do something with the zip file
}

一般来说,如果一个异步函数返回一些东西,那么使用它的代码也需要是异步的。

【讨论】:

  • 这绝对是有道理的——它不允许我让我的 useCallback 异步吗?
  • @Davtho1983 你把async 关键字放在哪里了?它必须直接在您的箭头函数之前,notuseCallback 之前。这绝对有效。 它不让我是什么意思?有错误吗? createURL 处理程序是否被称为事件处理程序?
  • 我有 const createURL = useCallback(async (node, reportHeight, reportWidth, imgHeight) => { ... let base64pdf = await getZip(btoa(fileName, pdf.output())); 。 ..我得到的错误是解析错误:不能在异步函数之外使用关键字'await'
  • @Davtho1983 是的,这可能是原因。你也可以在那里使用 async/await。让我更新我的答案。
  • @Davtho1983 为了保持一致,您也可以对 toJpeg 使用 async/await。否则,您还必须在 .then() 异步处理您的处理程序。
猜你喜欢
  • 1970-01-01
  • 2019-12-12
  • 2017-03-28
  • 2015-05-04
  • 1970-01-01
  • 1970-01-01
  • 2017-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多