📄
TypeScriptでreact-dropzoneを使ってドロップされたファイル名の表示
本記事は以下の記事のコードを参考にさせていただきました。
JavaScriptでreact-dropzoneの使い方を解説されています。
前提
- typescriptでreact-dropzoneを使用したい
-
npx create-react-app my-app --template typescript
でプロジェクトを作り、npm install react-dropzone
した "react": "^18.2.0",
"react-dropzone": "^14.2.2",
-
- ドロップされたファイルの名前を表示したいが、react-dropzoneから返されるacceptedFilesに
.path
がないというエラーが出る
import { useCallback, useMemo } from 'react';
import { useDropzone } from 'react-dropzone';
// ドロップされたときに実行する関数
const onDrop = useCallback((files: File[]) => {
// Do something with the files
console.log('files:', files);
}, []);
const { getRootProps, getInputProps, isDragActive, acceptedFiles } = useDropzone({ onDrop });
// ドロップされたファイルパスを表示するli要素を準備
// ここで.pathがないエラー
const files = useMemo(() =>
acceptedFiles.map(file => (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
)
), [acceptedFiles]);
解決方法
useDropzone()
で返されるacceptedFiles
の型がFile[]
になっているのが原因。react-dropzoneにFileWithPath
という型があるのでそれを使う。
import { useCallback, useMemo } from 'react';
import { useDropzone, FileWithPath } from 'react-dropzone';
const onDrop = useCallback((files: File[]) => {
// Do something with the files
console.log('files:', files);
}, []);
const { getRootProps, getInputProps, isDragActive, acceptedFiles } = useDropzone({ onDrop });
// 型を変更。もっと良い方法があるはず
const filesUpdated: FileWithPath[] = acceptedFiles;
const files = useMemo(() =>
filesUpdated.map(file => (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
)
), [filesUpdated]);
コード全体
App.tsx
import { useCallback, useMemo } from 'react';
import { useDropzone, FileWithPath } from 'react-dropzone';
const styleDiv = {
margin: "1%"
}
const style = {
width: 200,
height: 150,
border: "1px dotted #888"
};
function App() {
const onDrop = useCallback((files: File[]) => {
// Do something with the files
console.log('files:', files);
}, []);
const { getRootProps, getInputProps, isDragActive, acceptedFiles } = useDropzone({ onDrop });
const filesUpdated: FileWithPath[] = acceptedFiles;
const files = useMemo(() =>
filesUpdated.map(file => (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
)
), [filesUpdated]);
return (
<div style={styleDiv}>
<div {...getRootProps()} style={style}>
<input {...getInputProps()} />
{
isDragActive ?
<p>Drop the files here ...</p> :
<p>Drag 'n' drop some files here, or click to select files</p>
}
</div>
<aside>
<h4>Files</h4>
<ul>{files}</ul>
</aside>
</div>
);
}
export default App;
このように表示される。test.jpgをドロップした状態。
参考
- 同様の問題。
FileWithPath
をreact-dropzone
からimportして解決
- react-dropzoneのissue。同様の問題について
acceptedFiles
がFile
型になっているのはおかしいのではという指摘。FileWithPath
をreact-dropzone
からimportして解決
ここでは↓のように変換している
const fileList = (files: FileWithPath[]): ReactNode => (
files.map(file => (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
))
);
Discussion