【问题标题】:React - File selector component that can manage VERY large file count selectionsReact - 可以管理非常大的文件计数选择的文件选择器组件
【发布时间】:2023-01-10 17:39:29
【问题描述】:

我正在寻找一个可以从用户那里获取文件列表的组件。它只需要获取文件,而不是上传。上传过程已经实现,它只需要一个文件列表。该组件需要满足以下要求:

  • 限于只要目录选择
  • 支持通过文件对话框拖放到选择之上
  • 在一次回调中捕获所有选定的文件,这意味着仅一次状态更新
    • 文件列表也应该在上传前可以访问,以便可以在预览中使用
  • 返回所有文件的webkitRelativePath

我最接近实现这一点的是Antd'sUpload组件。这里的限制是捕获文件列表的唯一方法是使用它的onChange回调,它被调用一次每一个选定的文件。这意味着如果用户选择数千个文件,这在我的案例中是常见的情况,它将更新文件列表状态数千次,导致数千次重新呈现并最终导致网站崩溃。

const uploadProps = {
    accept: '*',
    multiple: true,
    customRequest: () => {},
    onRemove: (file: UploadFile) => {
        const index = props.fileList.indexOf(file)
        const newFileList = [...props.fileList]
        newFileList.splice(index, 1)
        props.setFileList(newFileList)
    },
    beforeUpload: () => {
        return false
    },
    onChange: (info: UploadChangeParam<UploadFile<any>>) => {
        if (JSON.stringify(info.fileList) !== JSON.stringify(props.fileList)) {
            console.log(info.fileList)
            props.setFileList(info.fileList)
        }
        if (info.fileList.length === 0 && props.progress !== 0) props.setProgress(0)
    },
    directory: true
}
<Dragger
    {...uploadProps}
    fileList={props.fileList.slice(fileListIndex, fileListIndex + 10)}
>
    <p className='ant-upload-text'>
        <b>Uploading to:</b> {S3_BUCKET.split('/').slice(1).join('/')}
    </p>
    <br></br>
    <p className='ant-upload-drag-icon'>
        <InboxOutlined />
    </p>
    <p className='ant-upload-text'>
        Browse or drag folder to upload
        <br />
        <strong>Uploading {props.fileList.length} files</strong>
        <br />
        Showing files {props.fileList.length ? fileListIndex + 1 : 0}-
        {Math.min(fileListIndex + 10, props.fileList.length)}
    </p>
</Dragger>

我尝试了其他几个库,但我得到的第二个最接近的库是 @rpldy/uploady 库。我包装了 Antd 的 Dragger 组件以利用其视觉方面与 rpldy 的 UploadyUploadDropZone 组件的功能方面。 Dropzone 组件满足前三个条件,但它不返回文件列表中文件的 webkitRelativePath

<Uploady autoUpload={false} accept={'*'} webkitdirectory>
    <UploadDropZone
        onDragOverClassName='drag-over'
        htmlDirContentParams={{ recursive: true }}
        dropHandler={async (e, getFiles) => {
            let fileList = await getFiles()
            props.setFileList(fileList)
            fileList.map((file) => console.log(file.webkitRelativePath)) // Empty log
            return fileList
        }}
    >
        <Dragger
            openFileDialogOnClick={false}
            customRequest={() => {}}
            onRemove={(file: UploadFile) => {
                const index = props.fileList.indexOf(file as unknown as File)
                const newFileList = [...props.fileList]
                newFileList.splice(index, 1)
                props.setFileList(newFileList)
            }}
            fileList={
                props.fileList.slice(
                    fileListIndex,
                    fileListIndex + 10
                ) as unknown as UploadFile[]
            }
        >
            <p className='ant-upload-text'>
                <b>Uploading to:</b> {S3_BUCKET.split('/').slice(1).join('/')}
            </p>
            <br></br>
            <p className='ant-upload-drag-icon'>
                <InboxOutlined />
            </p>
            <p className='ant-upload-text'>
                <>
                    Browse or drag folder to upload
                    <br />
                    <UploadButton text='Browse' />
                    <br />
                    <strong>Uploading {props.fileList.length} files</strong>
                    <br />
                    Showing files{' '}
                    {props.fileList.length
                        ? fileListIndex + 1 > props.fileList.length
                            ? setFileListIndex(fileListIndex - 10)
                            : fileListIndex + 1
                        : 0}
                    -{Math.min(fileListIndex + 10, props.fileList.length)}
                </>
            </p>
        </Dragger>
    </UploadDropZone>
</Uploady>

【问题讨论】:

    标签: reactjs typescript file upload


    【解决方案1】:

    不幸的是,这是由于浏览器实现决定造成的。

    我在这段代码sandbox 中重新创建了一个简单版本的解决方案。

    在 Firefox 中,我得到了预期的路径,而在 Chrome 中,路径如您所报告的那样是空的。

    webkitRelativePath 属性的 MDN 定义是:“文件路径相对于用户在其 webkitdirectory 属性集的元素中选择的目录。”

    所以这意味着它应该只要在 webkit 目录实际使用文件选择对话框时可用

    然而,你很幸运,因为我以前遇到过这个问题并内置了在文件名中保留路径的功能。您可以通过传递激活它:完整路径到 Rpldy 的上传拖放区使用的 html-dir-content 包:

    
    htmlDirContentParams={{ recursive: true, withFullPath: true }}
    
    

    生成的文件数据将如下所示:

    【讨论】:

      猜你喜欢
      • 2011-05-24
      • 1970-01-01
      • 1970-01-01
      • 2021-07-26
      • 2015-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多