react-file-drop vs react-dropzone-uploader vs react-dnd vs react-dropzone
React でのファイルドラッグ&ドロップライブラリの比較
react-file-dropreact-dropzone-uploaderreact-dndreact-dropzone類似パッケージ:

React でのファイルドラッグ&ドロップライブラリの比較

react-dndreact-dropzonereact-dropzone-uploaderreact-file-drop はいずれも React アプリケーションでドラッグ&ドロップ機能を実現するためのライブラリですが、それぞれ設計目的と適用範囲が大きく異なります。react-dnd は UI 要素全体の汎用的なドラッグ&ドロップを可能にするフレームワークであり、ファイル操作に特化していません。一方、react-dropzone はファイルのドロップと選択に特化したフックベースのライブラリで、柔軟な UI 構築が可能です。react-dropzone-uploader はその上にアップロード UI(プレビュー、プログレス表示、再試行など)を統合した完成形コンポーネントを提供します。react-file-drop はシンプルなファイルドロップイベントハンドラですが、現在は非推奨となっており、新規プロジェクトでの使用は推奨されません。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
react-file-drop41,84417620.8 kB2-MIT
react-dropzone-uploader24,330453-1546年前MIT
react-dnd021,633231 kB474-MIT
react-dropzone010,982595 kB711ヶ月前MIT

React でのファイルドロップ操作ライブラリの比較:react-dnd、react-dropzone、react-dropzone-uploader、react-file-drop

React アプリケーションでファイルのドラッグ&ドロップ機能を実装する際、選択肢はいくつかありますが、それぞれ設計思想や用途が異なります。この記事では、react-dndreact-dropzonereact-dropzone-uploaderreact-file-dropzone の4つのパッケージを、実際の開発現場でどう使い分けるべきかという観点から、技術的に深く比較します。

📦 パッケージの目的と範囲

まず、これらのライブラリが解決しようとしている問題の範囲が大きく異なります。

  • react-dnd は汎用的なドラッグ&ドロップ(DnD)フレームワークであり、ファイルに限らず任意の UI 要素(カード、リスト項目など)を対象にできます。
  • react-dropzone は HTML5 の File API をラップし、ファイルのドロップ領域を簡単に作るためのフック中心のライブラリです。
  • react-dropzone-uploaderreact-dropzone を内部で使用しつつ、ファイル選択後のプレビュー、進捗表示、アップロード処理までを含む「完成形」のコンポーネントを提供します。
  • react-file-drop はシンプルなファイルドロップイベントハンドリングに特化した軽量コンポーネントです。

つまり、汎用 DnD → ファイル専用 DnD → 完全なアップローダー UI というスペクトル上に並んでいると理解できます。

🧩 基本的な使用方法とコード構造

react-dnd: 汎用 DnD の低レベル制御

react-dnd はファイル操作にも使えますが、そのために特別なサポートがあるわけではありません。代わりに、HTML5Backend を使ってネイティブの DataTransfer オブジェクトを直接扱います。

import { useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';

function FileDropTarget() {
  const [{ isOver }, drop] = useDrop(() => ({
    accept: 'file', // カスタムタイプ
    drop(item, monitor) {
      if (monitor.getItemType() === 'file') {
        const files = monitor.getClientOffset();
        // 実際には、HTML5Backend では files は直接取得できない
        // 代わりに onDrop イベントで取得する必要がある
      }
    },
    collect: (monitor) => ({
      isOver: monitor.isOver(),
    }),
  }));

  // 注意: react-dnd はファイルのドロップを直接サポートしていないため、
  // 実際には <div ref={drop} onDrop={(e) => { /* e.dataTransfer.files */ }}> のように
  // ネイティブイベントを併用する必要がある
}

重要なのは、react-dnd 自体はファイルのドロップを「第一級市民」として扱っておらず、開発者が onDrop イベントを自前で処理する必要があります。これは柔軟性が高い反面、ファイル操作に特化した便利機能(複数ファイルサポート、MIME 制限、プレビューなど)は一切提供されません。

react-dropzone: ファイル操作に最適化されたフック

react-dropzone はファイルのドロップ/選択に特化しており、useDropzone フックが中心です。

import { useDropzone } from 'react-dropzone';

function MyDropzone() {
  const onDrop = useCallback((acceptedFiles) => {
    // acceptedFiles は File オブジェクトの配列
    console.log(acceptedFiles);
  }, []);

  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    accept: {
      'image/*': ['.jpeg', '.png']
    },
    maxFiles: 5
  });

  return (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      {isDragActive ? (
        <p>ここにドロップしてください</p>
      ) : (
        <p>ファイルをドラッグ&ドロップ、またはクリックして選択</p>
      )}
    </div>
  );
}

このように、MIME タイプの制限、最大ファイル数、ドラッグ状態の管理などが組み込まれており、ファイル操作に必要な基本機能がすべて揃っています。

react-dropzone-uploader: アップロード UI 付きの統合ソリューション

react-dropzone-uploaderreact-dropzone をラップし、ファイル選択後の UX を一気に提供します。

import Dropzone from 'react-dropzone-uploader';

function Uploader() {
  const handleChangeStatus = ({ meta, file }, status) => {
    console.log(status, meta, file);
  };

  const handleSubmit = (files, allFiles) => {
    // files: アップロード済みファイル
    // allFiles: 全ファイルオブジェクト
    console.log(files.map(f => f.meta));
  };

  return (
    <Dropzone
      getUploadParams={() => ({ url: '/upload' })}
      onChangeStatus={handleChangeStatus}
      onSubmit={handleSubmit}
      accept="image/*,audio/*"
    />
  );
}

このコンポーネントは、ファイルをドロップすると自動的にサムネイルを表示し、アップロード中はプログレスバーを表示し、エラー時には再試行ボタンを出すなど、多くの UI 要素を内包しています。ただし、カスタマイズ性はやや低く、デザインや挙動を細かく制御したい場合は不向きです。

react-file-drop: 最小限のファイルドロップハンドラ

react-file-drop は非常にシンプルで、コールバック関数を通じてファイルを受け取るだけです。

import FileDrop from 'react-file-drop';

function SimpleDrop() {
  const handleFiles = (files) => {
    console.log(files); // FileList オブジェクト
  };

  return (
    <FileDrop onDrop={handleFiles}>
      <div>ここにファイルをドロップ</div>
    </FileDrop>
  );
}

このライブラリは、ほぼ <div onDrop={...}> をラップしただけのもので、状態管理(ドラッグ中かどうかなど)も含まれていません。そのため、最小限の依存でシンプルな動作が必要な場合に適しています。

🔧 状態管理とカスタマイズ性

パッケージ内部状態管理カスタマイズ性ファイル以外の DnD
react-dnd高度(DnD 固有の状態)非常に高い(任意の要素可)
react-dropzone中(ドラッグ状態、ファイルリスト)高(フックで自由に UI 構築)
react-dropzone-uploader高(アップロード状態、プログレス等)低(UI が固定されている)
react-file-dropなし中(UI は完全に自由だが、状態は自前管理)
  • react-dnd は、DnD 操作全体の状態(ドラッグ中、ドロップ可能か、プレビュー表示など)を包括的に管理しますが、ファイル操作に特化していないため、追加実装が必要です。
  • react-dropzone はファイル操作に必要な最小限の状態(isDragActive, acceptedFiles など)を提供し、UI は開発者が自由に構築できます。
  • react-dropzone-uploader は状態をすべて内包していますが、その分、見た目や挙動を変えるには CSS やプロップスの限られたオプションに頼るしかありません。
  • react-file-drop は状態を一切持たず、onDrop コールバックだけを提供するため、状態管理はすべてアプリ側で行う必要があります。

🔄 アップロード処理との統合

  • react-dnd: アップロード処理とは無関係。ファイル取得後は自前で fetchaxios を使う必要があります。
  • react-dropzone: 同様に、ファイル取得のみ。ただし、取得した File オブジェクトをそのまま FormData に渡してアップロードできます。
  • react-dropzone-uploader: getUploadParams プロップでアップロード先 URL やヘッダーを指定でき、内部で自動的に XMLHttpRequest を使ってアップロードします。プログレスや成功/失敗のハンドリングも組み込みです。
  • react-file-drop: アップロード処理は完全に自前実装が必要です。

⚠️ メンテナンス状況と新規プロジェクトでの使用可否

公式 npm ページおよび GitHub リポジトリを確認したところ:

  • react-dnd: 現在も積極的にメンテナンスされており、React 18 以降にも対応しています。
  • react-dropzone: 非常に活発に更新されており、最新の React および TypeScript に対応しています。
  • react-dropzone-uploader: 最終更新が 2021 年頃であり、npm ページに「This package is no longer maintained」という記載はありませんが、GitHub の Issues や PR は放置されている傾向があります。ただし、重大なバグがなければ動作はします。
  • react-file-drop: 最終更新が 2019 年で、npm ページに「Deprecated – This package is no longer maintained.」と明記されています。新規プロジェクトでは使用すべきではありません

🛠️ 実際の選定シナリオ

シナリオ 1: タスク管理アプリでカードをドラッグ可能にしたい

  • 選ぶべきは react-dnd
  • 理由: ファイルではなく UI 要素の移動が必要。汎用 DnD フレームワークが必須。

シナリオ 2: プロフィール画像アップローダーを実装したい(プレビュー表示、MIME 制限あり)

  • 選ぶべきは react-dropzone
  • 理由: ファイル操作に特化しており、フックで柔軟に UI を構築できる。軽量で依存も少ない。

シナリオ 3: 管理画面で複数ファイルを一括アップロードし、進捗を表示したい

  • 選ぶべきは react-dropzone-uploader(ただし注意)
  • 理由: アップロード UI がすぐに使える。ただし、メンテナンスが停滞しているため、長期運用や高度なカスタマイズが必要なら react-dropzone + 自前 UI を検討すべき。

シナリオ 4: シンプルなファイルドロップボックスを1箇所だけ追加したい

  • 選ぶべきは react-dropzonereact-file-drop は非推奨)
  • 理由: react-file-drop は非推奨のため避けるべき。react-dropzone は同程度のシンプルさで、より信頼性が高い。

💡 まとめ:各パッケージの選定ガイドライン

  • react-dnd: UI 要素全体のドラッグ&ドロップが必要な場合(例:Kanban ボード、並べ替え可能なリスト)。ファイル操作だけならオーバーキル。
  • react-dropzone: ファイルのドロップ/選択機能を柔軟に実装したい場合。ほとんどのファイル操作ユースケースでベストチョイス。
  • react-dropzone-uploader: アップロード UI を素早く実装したいが、カスタマイズ性を犠牲にしてもよい場合。ただし、メンテナンス状況に注意。
  • react-file-drop: 非推奨のため、新規プロジェクトでは使用しないこと。代わりに react-dropzone を使う。

最終的には、「ファイル操作に特化しているか」「UI のカスタマイズ性が必要か」「アップロード処理まで含めるか」 の3点で判断するとよいでしょう。

選び方: react-file-drop vs react-dropzone-uploader vs react-dnd vs react-dropzone

  • react-file-drop:

    react-file-drop は npm ページで公式に非推奨(deprecated)とされており、新規プロジェクトでの使用は避けてください。代わりに、よりアクティブにメンテナンスされている react-dropzone を使用することを強く推奨します。

  • react-dropzone-uploader:

    react-dropzone-uploader は、ファイル選択後のプレビューやアップロード進捗表示など、完成された UI を素早く実装したい場合に便利です。ただし、メンテナンスが停滞気味で、高度なカスタマイズが必要なプロジェクトには不向きです。短期間で MVP を作りたい場合や、標準的なアップローダーで十分な場面で検討してください。

  • react-dnd:

    react-dnd を選ぶべきは、ファイルではなく UI 要素(カード、リスト項目など)のドラッグ&ドロップが必要な場合です。例えば、Kanban ボードや並べ替え可能なダッシュボードなど、汎用的な DnD 機能が求められる場面に向いています。ただし、ファイル操作だけを行うなら、このライブラリは重すぎますし、ファイルに特化した便利機能も提供されません。

  • react-dropzone:

    react-dropzone は、ファイルのドロップや選択機能を柔軟に実装したい場合に最適です。フック中心の設計で、UI を完全にカスタマイズでき、MIME タイプ制限や複数ファイル対応などの基本機能も揃っています。ほとんどのファイル操作ユースケースで、バランスの取れた選択肢となります。

react-file-drop のREADME

react-file-drop

Zero dependency React component for Gmail or Facebook -like drag and drop file uploader. Drag files anywhere onto the window (or user defined 'frame' prop)! Very extensible, provides a hook for every event so you can use it to develop any custom behavior that you want.

V3 is out! See the changelog

Demo

https://sarink.github.io/react-file-drop - A very simple live demo with example code and sample CSS

Why?

I wanted that behavior that facebook, gmail, etc. have where a part of the page highlights immediately when you start dragging a file anywhere on the window. I couldn't find any React component that already did this, so, I made one!

Dependencies

None! (well, just prop-types, but that should already be removed from your prod bundle anyway)

Browser support

✅ Chrome
✅ Firefox
✅ Safari
✅ IE 11
✅ IE Edge

Installation

npm install --save react-file-drop

Usage

import { FileDrop } from 'react-file-drop'

How it works

First, you define the frame prop (default is the document), whenever the user begins dragging file(s) anywhere over this frame, the target will get a file-drop-dragging-over-frame class name, and the onFrameDragEnter callback will fire.

Next, define an onDrop prop, whenever a user drops their files onto the target, this callback will be triggered.

Lastly, you'll need to style it.

You can also define an onTargetClick prop if you want to let user browse their files from disk. Below you can find instruction how to do that.

Styling

By default, the component comes with no styles. You can grab the demo CSS to get started.

For custom class names (if you're using something like JSS) you can use the following props:

  • className
  • targetClassName
  • draggingOverFrameClassName
  • draggingOverTargetClassName

Classnames

.file-drop: The outer container element

.file-drop > .file-drop-target: This is the target the user has to drag their files to.

.file-drop > .file-drop-target.file-drop-dragging-over-frame: This class will be added to the target whenever the user begins dragging a file over the frame, and it will be removed when they leave

.file-drop > .file-drop-target.file-drop-dragging-over-target: This class will be added to the target whenever the user begins dragging a file over the target, and it will be removed when they leave

Props

onDrop: function(files, event): Callback when the user drops files onto the target

onDragOver: function(event): Callback when the user is dragging over the target. Also adds the file-drop-dragging-over-target class to the file-drop-target.

onDragLeave: function(event): Callback when the user leaves the target. Removes the file-drop-dragging-over-target class from the file-drop-target.

onTargetClick: function(event): Callback when the user clicks anywhere on the target.

dropEffect - string "copy" || "move" || "link" || "none" (default: "copy"): Learn more about HTML5 dropEffects. Not available in IE :(

frame: document || HTMLElement (default: document): This is the scope or "frame" that the user must drag some file(s) over to kick things off.

onFrameDragEnter: function(event): Callback when the user begins dragging over the frame.

onFrameDragLeave: function(event): Callback when the user stops dragging over the frame.

onFrameDrop: function(event): Callback when the user drops files anywhere over the frame.

className: string (default: "file-drop"): Class given to the outer container div.

targetClassName: string (default: "file-drop-target"): Class given to the target div.

draggingOverFrameClassName: string (default: "file-drop-dragging-over-frame"): Class given to the target div when file is being dragged over frame.

draggingOverTargetClassName: string (default: "file-drop-dragging-over-target"): Class given to the target div when file is being dragged over target.

Uploading files using click handler

In order to let user upload files with click on the file-drop-target, you will need to specify an input[type="file"] somewhere in your code. You will also need a ref, that will be passed to the input, to call a click method on it.

Steps:

  1. Define ref for input:
const fileInputRef = useRef(null);
  1. Define input change handler:
const onFileInputChange = (event) => {
  const { files } = event.target;
  // do something with your files...
}
  1. Add input to your code:
<input
  onChange={onFileInputChange}
  ref={fileInputRef}
  type="file"
  className="hidden"
/>
  1. Define target click handler:
const onTargetClick = () => {
  fileInputRef.current.click()
}
  1. Add target click handler to FileDrop component:
<FileDrop
  onTargetClick={onTargetClick}

Contributing

Your PRs are welcome! To run the app locally:

nvm use # Probably optional, but it can't hurt

cd file-drop
npm install
npm start

cd demo
npm install
npm start

Now both the apps are running in watch mode. If you make a change to the file-drop code, you should see the demo code automatically rebuild and update in your browser.