网站搜索

javascript - 对上传文件进行异步验证(React Dropzone + TS)


我需要使用 React Dropzone 验证上传视频的时长。问题是我找到的每个方法都是异步的,而该库的验证函数应该是同步的。我如何在同步函数中运行异步代码?

获取视频时长功能:

async function getVideoDuration(videoFile: File | Blob) {
  return new Promise<number>((res, _) => {
    const video = document.createElement("video")
    video.preload = "metadata"
    video.onloadeddata = function () {
      res(video.duration)
    }
    video.src = URL.createObjectURL(videoFile)
  })
}

我的 React Zone 验证函数:

    validator(f) {
      let file: (File) | null
      if (f instanceof DataTransferItem) {
        file = f.getAsFile()
      } else file = f
      if (!file) return { message: "File Expected", code: "IvalidDragObject" }
      console.log(file)

      if (file.size > 5e8) return { message: "File too large (max 500 MB)", code: "FileTooLarge" }

      if (!file) return { message: "File Expected", code: "IvalidDragObject" }
const duration = await getVideoDuration(file) // 'await' expressions are only allowed within async functions and at the top levels of modules.

      if (duration > 15 * 60) {
        return { message: "File Duration should be less than 15 minutes", code: "LargeFileDuration" }
      }

      return null
    },

其他的解决方法是使用 getFilesFromEvent 函数,并将自定义属性传递给文件,但它提供的事件非常不同,实现起来很繁琐。

答案#1

我已经在这里分叉了这个项目,并进行了必要的更改以支持异步验证。请注意,目前并不支持 noDragEventsBubbling 参数。只需传入一个异步(或同步)验证回调函数,如下所示,并按原本的用途使用。

import { useDropzone } from 'react-dropzone'

function MyDropzone() {
  const onDrop = useCallback(acceptedFiles => {
    // Do something with the files
  }, [])
  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    validator: async (file) => {
      // do validation here
    }
  })

  return (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      {
        isDragActive ?
          <p>Drop the files here ...</p> :
          <p>Drag 'n' drop some files here, or click to select files</p>
      }
    </div>
  )
}