如何使用 react-dropzone 在 React 中创建拖放文件上传

介绍

react-dropzone 是一个 HTML5 兼容的 React 组件,用于处理文件的拖放。

HTML5 支持使用<input type="file" />. react-dropzone为您提供附加功能,例如自定义放置区、显示预览以及限制文件类型和数量。

注意:如果您使用 Vue 而不是 React,请参阅我们的vue-dropzone.

在本教程中,您将了解如何添加react-dropzone到您的 React 项目并探索它提供的一些功能。

先决条件

要完成本教程,您需要:

本教程已通过 Node v15.3.0、npmv7.4.0、reactv17.0.1 和react-dropzonev11.2.4 验证。

步骤 1 — 设置项目

从使用create-react-app生成 React App 开始,然后安装依赖项:

  • npx create-react-app react-dropzone-example

切换到新的项目目录:

  • cd react-dropzone-example

安装react-dropzone

  • npm install react-dropzone@11.2.4

此时,您有一个带有react-dropzone.

第 2 步 – 添加 Dropzone 组件

react-dropzone 具有默认设置,允许您以最少的配置添加它。

至少,您需要一个onDrop属性来处理丢弃的文件和一些号召性用语,以帮助限制任何用户混淆:

src/DropzoneComponent.js
import React, { useCallback } from 'react';
import { useDropzone } from 'react-dropzone';

function DropzoneComponent() {
  const onDrop = useCallback(acceptedFiles => {
    console.log(acceptedFiles);
  }, []);

  const {
    getRootProps,
    getInputProps
  } = useDropzone({
    onDrop
  });

  return (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      <div>Drag and drop your images here.</div>
    </div>
  )
}

export default DropzoneComponent;

此代码为您的应用程序提供拖放功能。

注意:值得注意的是,即使react-dropzone被设计为拖放文件,默认情况下它也接受点击事件到放置区,这将启动文件选择对话框。

将组件添加到您的 React 应用程序:

源代码/App.js
import DropzoneComponent from './DropzoneComponent';

function App() {
  return (
    <div className="App">
      <DropzoneComponent />
    </div>
  );
}

export default App;

运行您的应用程序并在 Web 浏览器中观察它。您应该会看到一个带有文本的 div: Drag and drop your images here

尝试将各种文件拖放到 React Dropzone 组件。该代码当前使用 aconsole.log来显示文件。从上传的文件的信息包括namelastModifiedsize,和type

此时,您有一个使用默认配置的可工作的 React Dropzone 组件。react-dropzone文档附加的配置选项

第 3 步 – 设置 Dropzone 组件的样式

默认情况下,react-dropzone将没有样式。该文档提供了通用外观的样式,该外观使用 flexbox 和虚线边框的组合来向用户指示拖放文件的区域。

react-dropzone还支持组件主动与 ( isDragActive)交互、接受文件 ( isDragAccept) 或拒绝文件 ( isDragReject)时的道具

当应用于 JPEG 和 PNG 图像文件类型时重新访问DropzoneComponent并修改它以使用isDragActiveisDragAcceptisDragReject

src/DropzoneComponent.js
import React, { useCallback, useMemo } from 'react';
import { useDropzone } from 'react-dropzone';

const baseStyle = {
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'center',
  padding: '20px',
  borderWidth: 2,
  borderRadius: 2,
  borderColor: '#eeeeee',
  borderStyle: 'dashed',
  backgroundColor: '#fafafa',
  color: '#bdbdbd',
  transition: 'border .3s ease-in-out'
};

const activeStyle = {
  borderColor: '#2196f3'
};

const acceptStyle = {
  borderColor: '#00e676'
};

const rejectStyle = {
  borderColor: '#ff1744'
};

function DropzoneComponent(props) {
  const onDrop = useCallback(acceptedFiles => {
    console.log(acceptedFiles);
  }, []);

  const {
    getRootProps,
    getInputProps,
    isDragActive,
    isDragAccept,
    isDragReject
  } = useDropzone({
    onDrop,
    accept: 'image/jpeg, image/png'
  });

  const style = useMemo(() => ({
    ...baseStyle,
    ...(isDragActive ? activeStyle : {}),
    ...(isDragAccept ? acceptStyle : {}),
    ...(isDragReject ? rejectStyle : {})
  }), [
    isDragActive,
    isDragReject,
    isDragAccept
  ]);

  return (
    <div {...getRootProps({style})}>
      <input {...getInputProps()} />
      <div>Drag and drop your images here.</div>
    </div>
  )
}

export default DropzoneComponent;

此代码将产生以下结果:

带有自定义样式的 React Dropzone 的屏幕截图

更改接受和拒绝组件的外观有助于向用户提供有关其文件是否有效的反馈。

第 4 步 – 添加图像预览

预览是在组件中拖放的图像的副本。这有助于向用户提供视觉反馈以验证他们选择的图像文件的内容。

预览7.0.0版本中去除,然而,文档提供用于与的组合readding它的替代Object.assign()URL.createObjectURL()

重新访问DropzoneComponent并修改它以使用preview

src/DropzoneComponent.js
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDropzone } from 'react-dropzone';

const baseStyle = {
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'center',
  padding: '20px',
  borderWidth: 2,
  borderRadius: 2,
  borderColor: '#eeeeee',
  borderStyle: 'dashed',
  backgroundColor: '#fafafa',
  color: '#bdbdbd',
  transition: 'border .3s ease-in-out'
};

const activeStyle = {
  borderColor: '#2196f3'
};

const acceptStyle = {
  borderColor: '#00e676'
};

const rejectStyle = {
  borderColor: '#ff1744'
};

function DropzoneComponent(props) {
  const [files, setFiles] = useState([]);

  const onDrop = useCallback(acceptedFiles => {
    setFiles(acceptedFiles.map(file => Object.assign(file, {
      preview: URL.createObjectURL(file)
    })));
  }, []);

  const {
    getRootProps,
    getInputProps,
    isDragActive,
    isDragAccept,
    isDragReject
  } = useDropzone({
    onDrop,
    accept: 'image/jpeg, image/png'
  });

  const style = useMemo(() => ({
    ...baseStyle,
    ...(isDragActive ? activeStyle : {}),
    ...(isDragAccept ? acceptStyle : {}),
    ...(isDragReject ? rejectStyle : {})
  }), [
    isDragActive,
    isDragReject,
    isDragAccept
  ]);

  const thumbs = files.map(file => (
    <div key={file.name}>
      <img
        src={file.preview}
        alt={file.name}
      />
    </div>
  ));

  // clean up
  useEffect(() => () => {
    files.forEach(file => URL.revokeObjectURL(file.preview));
  }, [files]);

  return (
    <section>
      <div {...getRootProps({style})}>
        <input {...getInputProps()} />
        <div>Drag and drop your images here.</div>
      </div>
      <aside>
        {thumbs}
      </aside>
    </section>
  )
}

export default DropzoneComponent;

注意:为避免内存泄漏,您需要调用URL.revokeObjectURL(file.preview)以避免不必要地存储预览。

现在,无论何时删除一个(或多个)文件,该文件都会附加到状态并显示预览。

结论

在本教程中,您react-dropzone了解以及如何在 React 应用程序中使用它来为文件上传提供高级拖放功能。

如果您想了解有关 React 的更多信息,请查看我们的How To Code in React.js系列,或查看我们的 React 主题页面以获取练习和编程项目。

觉得文章有用?

点个广告表达一下你的爱意吧 !😁