react-dropzoneというファイルアップロードに便利なライブラリを知ったので調べた
react-dropzone は、ファイルのドラッグ&ドロップインターフェースをReactアプリケーションに簡単に追加するためのライブラリ
React Dropzoneの主な機能は以下
- ファイルのドラッグアンドドロップ対応
- クリックによるファイル選択
- 一度に複数ファイルのサポート(アップロード可能なファイルの数やタイプを制限するオプションも提供されている)
- ファイルタイプの制御
- カスタマイズ可能なUI(ドロップゾーンの外観やインタラクションは柔軟にカスタマイズできる)
- フックベースのAPI
実装例
import React from 'react'; import { useDropzone } from 'react-dropzone'; function MyDropzone() { const { getRootProps, getInputProps, acceptedFiles } = useDropzone({ onDrop, // ユーザーがファイルをドロップしたときに呼び出されるコールバック関数 accept: 'image/*', // どのファイルタイプを受け入れるかを制御 multiple: true, disabled: false, noClick: true, noKeyboard: true, }); const files = acceptedFiles.map(file => ( <li key={file.path}> {file.path} - {file.size} bytes </li> )); return ( <div {...getRootProps({ className: 'dropzone' })}> <input {...getInputProps()} /> <p>Drag 'n' drop some files here, or click to select files</p> <ul>{files}</ul> </div> ); }
getRootProps
をpropsとして渡されたコンポーネントがドロップゾーンになる
acceptはオブジェクトで、{ "image/jpeg": [".jpg", ".jpeg"] }
のようにMIME-typeと拡張子をセットで指定もできる
カスタムバリデーション
独自のvalidationが定義できる
例えば、以下の精査条件を設けるとする
実装は以下のようになる
import React, { useCallback } from 'react'; import { useDropzone } from 'react-dropzone'; function MyDropzone() { const maxSize = 2 * 1024 * 1024; // 2MB const customValidator = (file) => { const errors = []; // ファイルサイズのチェック if (file.size > maxSize) { errors.push({ code: "file-too-large", message: `ファイルサイズが2MBを超えています: ${file.name}`, }); } // 画像の縦横比のチェック return new Promise((resolve) => { const img = new Image(); img.src = URL.createObjectURL(file); img.onload = () => { const aspectRatio = img.width / img.height; if (aspectRatio < 0.5 || aspectRatio > 2) { errors.push({ code: "invalid-aspect-ratio", message: `縦横比が許可されている範囲外です: ${file.name}`, }); } resolve(errors.length ? errors : null); }; }); }; const onDrop = useCallback((acceptedFiles, rejectedFiles) => { acceptedFiles.forEach((file) => { console.log('Accepted file:', file); }); rejectedFiles.forEach((file) => { file.errors.forEach((err) => { console.error(`${file.file.name} - ${err.message}`); }); }); }, []); const { getRootProps, getInputProps } = useDropzone({ accept: 'image/jpeg, image/png', validator: customValidator, onDrop, }); return ( <div {...getRootProps({ className: 'dropzone' })}> <input {...getInputProps()} /> <p>ファイルをここにドラッグ&ドロップ、またはクリックして選択</p> </div> ); } export default MyDropzone;