React ファイル選択のコンポーネントを作成する
React
+TypeScript
の環境で、ファイル選択のコンポーネントを作成します。
完成品
最低限の機能ですが、以下のように実装します。
import { useCallback, useRef, useState } from 'react';
const App = () => {
const [files, setFiles] = useState<File[]>([]); // 選択したファイルを配列で格納
const attachRef = useRef<HTMLInputElement>(null); // ファイル選択のコントロールを参照
// ファイル選択イベント
const handleInpuFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files == null) return; // ファイルがない場合は処理終了
const files = Array.from(e.target.files); // FileListを配列に変換
setFiles((current) => current.concat(files)); // 選択したファイルを変数に追加
if (attachRef.current) attachRef.current.value = ''; // 内部的なファイルの選択状態をクリア
}, []);
return (
<>
<div>
{files.map((f) => (
<div key={f.name}>{f.name}</div>
))}
</div>
<div>
<input type="button" value="参照" onClick={() => attachRef.current?.click()}></input>
<input type="file" style={{ display: 'none' }} ref={attachRef} multiple onChange={handleInpuFileChange}></input>
</div>
</>
);
};
export default App;
解説
複数のファイルが選択できるように、選択したファイルは配列でstate
で保持しています。
const [files, setFiles] = useState<File[]>([]); // 選択したファイルを配列で格納
選択したファイルのファイル名を1件ずつループで画面に出力しています。
ここではkeyをname
(ファイル名)としているため、同名のファイルを複数選択するとエラーになります。
実際はユニークなIDなどもファイルとセットで一緒にstate
で保持する形になると思います。
<div>
{files.map((f) => (
<div key={f.name}>{f.name}</div>
))}
</div>
ファイル選択のコントロール(input type="file"
)をそのまま使用してもよいですが、ブラウザによってスタイルが異なるので、今回は非表示としています。
参照ボタンクリックで、内部的にファイル選択のボタンをクリックしています。
ファイル選択のボタンを参照するため、attachRef
という変数でファイル選択の要素を参照できるようにしています。
<div>
<input type="button" value="参照" onClick={() => attachRef.current?.click()}></input>
<input type="file" style={{ display: 'none' }} ref={attachRef} multiple onChange={handleInpuFileChange}></input>
</div>
ファイル選択イベントにて、e.target.files
で選択したファイルを取得できます。
FileList
の型で取得されますので、扱いやすいようにArray.From
で配列(File[]
)に変換しています。
ファイルの配列をstate
に追加し、最後にファイルコントロールの選択状態をクリアします。
クリアしないと、同じファイルを再度選択したときに、onChange
イベントが発生しなくなってしまいます。
// ファイル選択イベント
const handleInpuFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files == null) return; // ファイルがない場合は処理終了
const files = Array.from(e.target.files); // FileListを配列に変換
setFiles((current) => current.concat(files)); // 選択したファイルを変数に追加
if (attachRef.current) attachRef.current.value = ''; // 内部的なファイルの選択状態をクリア
}, []);
このコンポーネントに対して、React ドラッグ&ドロップでファイルを選択するでドラッグ&ドロップでファイルを追加する方法を紹介しています。