これは何
Reactのリハビリ+ついでに触ったことのないnext.jsを触ってみようといろいろ遊んでました。D&Dでドロップされてきたファイルの中身を読み取る処理を書いていたのですが、ファイル読み込み部分で若干ハマったので備忘録として残します。
やりたかったこと
- Finderから複数のmp3ファイルをブラウザにD&Dでドロップする
- mp3ファイルのメタデータを読み込む
- 読み取ったメタデータをリストに表示する
だめだったコード
最初は以下のようにドラッグイベントからitems
を引っ張ってきて、そのアイテムを全て回して取得しようとしました。1つ目のファイルは読み取れましたが、それ以降のファイルの type
を読んだ時に中身がなくなっていて読み取れない現象が発生してました。
const handleDrop = async (e: DragEvent) => {
const items = e.dataTransfer?.items;
if (items) {
const newList = [...data];
for (const el of Array.from(items)) {
if (el.type === "audio/mpeg") {
const audioFile = el.getAsFile();
if (audioFile) {
// ファイルのメタデータを読み取る処理
const audioFileBuffer = await audioFile.arrayBuffer();
const tags = await mm.parseBuffer(Buffer.from(audioFileBuffer));
newList.push({
id: newList.length + 1,
title: tags.common.title ?? audioFile.name,
artist: tags.common.artist ?? "",
});
}
}
}
setData(newList);
}
}
読み取りできたコード
以下のようにforを回す前に getAsFile()
までやってしまう形で実装したところ、うまく全ファイルの内容を取得することができました。
forループの中でawaitとかしているので、その処理の間にDragEventから情報が取れなくなってしまうんですかね。このへん公式ドキュメントからその辺の情報を拾おうとしたのですが、まだ見つけられてないですね。。。逆に getAsFile()
ってなんか名前的に重そうですけど Promise じゃないんですね。
const handleDrop = async (e: DragEvent) => {
const items = e.dataTransfer?.items;
if (items) {
const newList = [...data];
const files = Array.from(items)
.filter((el) => el.type === "audio/mpeg")
.map((el) => el.getAsFile());
for (const audioFile of files) {
if (audioFile) {
// ファイルのメタデータを読み取る処理
const audioFileBuffer = await audioFile.arrayBuffer();
const tags = await mm.parseBuffer(Buffer.from(audioFileBuffer));
newList.push({
id: newList.length + 1,
title: tags.common.title ?? audioFile.name,
artist: tags.common.artist ?? "",
});
}
}
setData(newList);
}
}