【Reactドラッグ&ドロップでファイルのアップロード】react-dropzoneの使い方
はじめに
input
タグのtype属性を'file'
に設定することでファイルのアップロードが可能ですが、UIをよりわかりやすくするために、以下のようにドラッグ&ドロップ機能を用いてファイルをアップロードできるようにします。
react-dropzone
react-dropzone
は、Reactのコンポーネントライブラリでありドラッグ&ドロップインターフェースを簡単に実装できるライブラリです。
インストールしてください。
npm install react-dropzone
ファイルアップロード用のコンポーネント作成
components
フォルダにファイルアップロード用のコンポーネントを作成します。
今回は、DropzoneComponent.tsx
という名前でファイルを作成します。
mkdir -p src/app/components && touch src/app/components/DropzoneComponent.tsx
下記の内容を記述してください。
import { CSSProperties, useCallback, useState } from 'react';
import { useDropzone } from 'react-dropzone';
const styles: CSSProperties = {
border: '2px dashed #cccccc',
borderRadius: '5px',
padding: '20px',
textAlign: 'center',
cursor: 'pointer',
};
export function Dropzone = () => {
const [file, setFile] = useState<File | null>(null);
const onDrop = useCallback((acceptedFiles: File[]) => {
setFile(acceptedFiles[0]);
console.log(acceptedFiles);
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
return (
<div {...getRootProps()} style={styles}>
<input {...getInputProps()} />
{isDragActive && <p>ここにファイルをドロップしてください。</p>}
{!file && !isDragActive && (
<p>
ファイルをドラッグ&ドロップするか、ここをクリックしてファイルを選択してください。
</p>
)}
{file && (
<div>
<p>アップロードされたファイル名 </p>
<p>{file.name} </p>
</div>
)}
</div>
);
};
onDrop
ファイルドロップエリアにファイルがドロップされた際に呼び出される非同期関数
FormData
onDragEnter
ドロップゾーンにファイルがドラッグされて入った時に発生します。
onDragOver
ファイルがドロップゾーン上にある間、継続的に発生します。
onDragLeave
ファイルがドロップゾーンから出た時に発生します。
オプション
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
noClick: true,
noKeyboard: true,
accept: {
'image/png': ['.png'],
'image/jpeg': ['.jpeg'],
'image/gif': ['.gif'],
},
});
noClick
true
に設定されている場合、ドロップゾーンをクリックしてファイル選択ダイアログを開くことはできません。つまり、ユーザーはドラッグアンドドロップのみを使用してファイルをアップロードできるようになります。
noKeyboard
true
に設定されている場合、キーボードを使ったインタラクション(例えば、エンターキーを押してファイル選択ダイアログを開く)が無効になります。
accept
どのファイルタイプを受け付けるかを指定します。
ページコンポーネントでの使用
<DropzoneComponent />
を追記してください。
isDragActive
isDragActive
は、ドラッグ中のアイテムがドロップゾーンの範囲内にある場合にtrue
になります。
Types of property 'textAlign' are incompatible.
下記の場合、style={styles}
で
const styles = {
border: '2px dashed #cccccc',
borderRadius: '5px',
padding: '20px',
textAlign: 'center',
cursor: 'pointer',
};
次のようなエラーが出ます。
これは、styles
オブジェクトの各プロパティの型は自動的に推論され、特定の文字列リテラル型ではなく、string
型として扱われることが多いです。これが原因で、Reactのstyle
プロパティが期待する特定の文字列リテラル型と一致せず、エラーが発生することがあります。
Type '{ border: string; borderRadius: string; padding: string; textAlign: string; cursor: string; }' is not assignable to type 'Properties<string | number, string & {}>'.
Types of property 'textAlign' are incompatible.
Type 'string' is not assignable to type 'TextAlign | undefined'.ts(2322)
index.d.ts(2908, 9): The expected type comes from property 'style' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'
解決するには、textAlign: 'center'
をtextAlign: 'center' as const
に変更、
またはCSSProperties
型を明示的に指定して、textAlign
の値として'center'
が適切であることを保証してください。
const styles: CSSProperties = {
border: '2px dashed #cccccc',
borderRadius: '5px',
padding: '20px',
textAlign: 'center',
cursor: 'pointer',
};
as const
as const
は、TypeScriptにリテラル型を使うように指示します。
リテラル型は、値が特定の値であることを示す型です。つまり、'center' as const
とすることで、その値が厳密に'center'
であると型付けされます。
終わりに
何かありましたらお気軽にコメント等いただけると助かります。
ここまでお読みいただきありがとうございます🎉
Discussion