![見出し画像](https://assets.st-note.com/production/uploads/images/125281425/rectangle_large_type_2_552b90568e4255a0f50a60e6cf0b6346.png?width=800)
inertia.jsでreact-dropzoneを使ってみた結果
install
npm install react-dropzone
雛形
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'
import { Head, Link, router, useForm } from '@inertiajs/react'
import { useDropzone } from 'react-dropzone';
import { useState, useCallback } from 'react';
export default function ArtifactIndex({ auth }) {
const [errorMessage, setErrorMessage] = useState('');
const onDrop = useCallback((acceptedFiles, fileRejections) => {
// Upload function here
});
const { getRootProps, getInputProps } = useDropzone({
onDrop,
maxFiles: 1,
});
return (
<AuthenticatedLayout
user={auth.user}
header={
<h2 className="font-semibold text-xl text-gray-800 leading-tight">
Artifacts
</h2>
}
>
<Head title="Artifats" />
<div className="py-6 px-4 mx-auto max-w-screen-xl">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 text-gray-900">
</div>
</div>
</div>
</div>
</AuthenticatedLayout>
)
}
maxFilesでファイルの数を制限している
デザイン
{/* Dropzone area */}
<div {...getRootProps({
className: 'p-6 dropzone',
'data-tooltip-id': errorMessage ? 'errorTooltip' : ''
})}>
<input {...getInputProps()} />
<p className="border-2 border-dashed border-blue-500 rounded-md p-4 text-center text-blue-500 hover:border-blue-700">
ドラッグアンドドロップするかクリックしてファイルを選択してください
</p>
</div>
こんな感じで自分で作る。data-tooltip-id はエラーのときのツールチップ用だが、まあ、今はなんとなく置いてある
![](https://assets.st-note.com/img/1703228845057-0kndZisFz8.png?width=1200)
送信先とかをちゃんと書く
ここれはファイルをartifacts.storeに送信したい。とりあえずcontrollerではdumpを用意しておくだけ
public function store(Request $request)
{
dd($request->all());
}
アップロードするにはjsxのこの箇所だ
const onDrop = useCallback((acceptedFiles, fileRejections) => {
// Upload function here
});
こうする
export default function ArtifactIndex({ auth }) {
const [errorMessage, setErrorMessage] = useState('');
const onDrop = useCallback((acceptedFiles, fileRejections) => {
// FormData オブジェクトを作成
const formData = new FormData();
// 受け取ったファイルを FormData に追加
acceptedFiles.forEach(file => {
formData.append('files[]', file);
});
router.post(route("artifacts.store"), formData, {
forceFormData: true,
});
![](https://assets.st-note.com/img/1703229169206-Ccfs3SiOJ4.png?width=1200)
このようにアップロードできていることが理解できるが、ただ、2つファイルを放りこんだときは無反応になる
エラーハンドリング
export default function ArtifactIndex({ auth }) {
const [errorMessage, setErrorMessage] = useState('');
const onDrop = useCallback((acceptedFiles, fileRejections) => {
setErrorMessage('');
if (fileRejections.length > 0) {
setTimeout(() => { setErrorMessage(''); }, 2000);
return;
} else {
setErrorMessage('');
}
// FormData オブジェクトを作成
const formData = new FormData();
// 受け取ったファイルを FormData に追加
acceptedFiles.forEach(file => {
formData.append('files[]', file);
});
router.post(route("artifacts.store"), formData, {
forceFormData: true,
});
こんな感じでfileRejectionsにエラーの状態とかがあるので、それに応じてstateにいれている。あとはこれを表示すればいい
{/* Dropzone area */}
<div {...getRootProps({
className: 'p-6 dropzone',
'data-tooltip-id': errorMessage ? 'errorTooltip' : ''
})}>
<input {...getInputProps()} />
<p className="border-2 border-dashed border-blue-500 rounded-md p-4 text-center text-blue-500 hover:border-blue-700">
ドラッグアンドドロップするかクリックしてファイルを選択してください
</p>
{/* エラーメッセージ表示 */}
{errorMessage && (
<p className="text-red-500 text-center mt-2">
{errorMessage}
</p>
)}
</div>
![](https://assets.st-note.com/img/1703229632268-Kd6az2FprR.png?width=1200)
tooltipを使ったりする
まあこれでもいいんだけど
とかやったのでこれを使ってみると
npm install react-tooltip
import { Tooltip } from 'react-tooltip';
でimportしといて
{/* Dropzone area */}
<div {...getRootProps({
className: 'p-6 dropzone',
'data-tooltip-id': errorMessage ? 'errorTooltip' : ''
})}>
<input {...getInputProps()} />
<p className="border-2 border-dashed border-blue-500 rounded-md p-4 text-center text-blue-500 hover:border-blue-700">
ドラッグアンドドロップするかクリックしてファイルを選択してください
</p>
</div>
{errorMessage && (
<Tooltip
id="errorTooltip"
place="top"
variant="error"
content={errorMessage}
isOpen={true}
/>
)}
みたいにする。でもこれだと出っぱなしになるから
setErrorMessage('');
if (fileRejections.length > 0) {
setErrorMessage("一度にアップロードできるのは1つのファイルのみです。");
setTimeout(() => { setErrorMessage(''); }, 2000);
return;
} else {
setErrorMessage('');
}
のようにTimeoutさせておいた。この辺はフロントエンドでぐにゅぐにゅすると楽なところであるな。
![](https://assets.st-note.com/production/uploads/images/125280223/picture_pc_b685bd1e7a53345ab86a8f49cfd61ebd.gif?width=1200)
docxだけに絞るとかする
const { getRootProps, getInputProps } = useDropzone({
onDrop,
maxFiles: 1,
accept: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
});
でもこれ動かないんだって
setErrorMessage('');
// 拡張子に基づく追加の検証
if (!acceptedFiles.every(file => file.path.endsWith('.docx'))) {
setErrorMessage('サポートされているファイル形式は.docxのみです。');
setTimeout(() => { setErrorMessage(''); }, 3000);
return;
}
if (fileRejections.length > 0) {
// エラーの原因によって異なるメッセージを設定
const { errors } = fileRejections[0];
if (errors.some(e => e.code === 'too-many-files')) {
setErrorMessage('一度にアップロードできるのは1つのファイルのみです。');
} else if (errors.some(e => e.code === 'file-invalid-type')) {
setErrorMessage('サポートされているファイル形式は.docxのみです。');
}
setTimeout(() => { setErrorMessage(''); }, 3000);
return;
}
まあこの辺のコードは大概AIに書かせているから詳しくみてないけど動いてはいるみたいよ
この記事が気に入ったらサポートをしてみませんか?