【JavaScript】Fileを扱えるようになりたいんだ
BlobやFileに関する知識が不足していたので、色々試してみる。
以下のコードを書いてみた。
import React from "react";
const index = () => {
return (
<>
<h1>index</h1>
<div>
<form>
<input type="file" onChange={(e) => console.log(e.target.files)} />
</form>
</div>
</>
);
};
export default index;
実行結果は以下のようになる。
FileListオブジェクトを取得できた。Fileオブジェクトを格納している。
このFileListオブジェクトは、<input>要素でtype=fileとしたときに返される。
例えばinputタグに multipleを指定した場合、複数のファイルを扱うことができる。
その場合以下のようになる。
2つのFileオブジェクトがFileListオブジェクトに格納されている。
Fileって?
によると、
ファイルについての情報を提供したり、ウェブページ内の JavaScript からその内容にアクセスできるようにしたりします。
とありました。
納得。例えばFileオブジェクトのtypeプロパティを見てみると"image/jpeg"とあり、画像ファイルに関する拡張子の情報を取得することができています。
ドキュメントに以下のような記述が。
File オブジェクトは特別な種類の Blob オブジェクト
Blobオブジェクトを拡張することによって、Fileオブジェクトが作られています。
BlobオブジェクトとFileオブジェクトの違いについて、以下のqiita記事が分かりやすかったです。
FileとBlobについて、少し把握したところで、
以下のメソッドを使って、
input type="file" に指定した画像データをプレビューするような簡単なプログラムを作ってみる。
できた。
画像データを選択すると、画像が表示される。
import React, { ChangeEvent, useEffect, useState } from "react";
const index = () => {
const [fileData, setFileData] = useState<File | undefined>(undefined);
const [imageUrl, setImageUrl] = useState<string | undefined>(undefined);
useEffect(() => {
if (typeof fileData === "object") {
setImageUrl(URL.createObjectURL(fileData));
} else {
setImageUrl(undefined);
}
}, [fileData]);
return (
<>
<h1>index</h1>
<div>
<form>
<input
type="file"
onChange={(e: ChangeEvent<HTMLInputElement>) => {
e.target.files &&
e.target.files[0] &&
setFileData(e.target.files[0]);
}}
/>
</form>
</div>
<div>
{imageUrl && (
<img src={imageUrl} alt="プレビュー画像" style={{ width: "300px" }} />
)}
</div>
</>
);
};
export default index;
Blob URL と Data URLの違いについて以下の記事が分かりやすかった。
FileReader.readAsDataURL の代わりに URL.createObjectURLを勧めている記事。
URL の寿命は、それを作成したウィンドウ内の document と結び付けられています。
とあり、createObjectURLで取得したURLを、アプリケーションのタブを閉じた後に入力すると、
ERR_FILE_NOT_FOUND
となる。
URL.revokeObjectURL() 静的メソッドは、以前に URL.createObjectURL() を呼び出して生成された既存のオブジェクト URL を解放します。 オブジェクト URL を使い終わったら、このメソッドを呼び出して、ファイルへの参照をこれ以上保持しないようにブラウザーに知らせます。
以下の例で作ったプログラムを改善する。
画像を変えたときに、変える前に表示するために使用していたオブジェクトURLを解放する。
import React, { ChangeEvent, useEffect, useState } from "react";
const index = () => {
const [fileData, setFileData] = useState<File | undefined>(undefined);
const [imageUrl, setImageUrl] = useState<string | undefined>(undefined);
useEffect(() => {
if (typeof fileData === "object") {
+ imageUrl && URL.revokeObjectURL(imageUrl);
setImageUrl(URL.createObjectURL(fileData));
} else {
setImageUrl(undefined);
}
}, [fileData]);
return (
<>
<h1>index</h1>
<div>
<form>
<input
type="file"
onChange={(e: ChangeEvent<HTMLInputElement>) => {
e.target.files &&
e.target.files[0] &&
setFileData(e.target.files[0]);
}}
/>
</form>
</div>
<div>
{imageUrl && (
<img src={imageUrl} alt="プレビュー画像" style={{ width: "300px" }} />
)}
</div>
</>
);
};
export default index;