🌝

ReactでFileのアップロードボタンをカスタマイズする

2 min read

こんにちはハトです。色々の記事をあさっているうちに、ファイルアップロードのやり方の知見がたまったので共有します。

基本

以下のようにinputタグにfileを指定すれば、ファイルエクスプローラー(もしくはファインダー)が開きます。選択したファイルはonChangeコールバックの引数に渡されます。

<input type='file' onChange={onFileInputChange}/>

onChangeコールバックの引数ではe.target.files に選択したファイルが格納されています。

  const onFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    console.log(e.target.files);
  };

ちなみにaccept="image/*" 属性を渡すと画像のみ選択できるようになります。

<input type='file' accept="image/*" onChange={onFileInputChange}/>

アップロードボタンのカスタマイズ

上記「基本」セクションでファイルアップロードはできます。ただ標準のinputボタンはださいので、なんとかカスタマイズしたいところです。

やり方は、

  • 先程のinputタグにhidden属性を渡し、非表示にする。
  • useRefを利用して、inputタグの生domをrefに格納する。
  • 別にボタンを用意する。このボタンをクリックすると、先程のrefを用いて遠隔でinputタグをクリックする。

[応用編] ファイルインプットをコンポーネント化する

先程の「アップロードボタンのカスタマイズ」セクションのやり方では、常にボタンとinputタグを同一のコンポーネントに収めなければいけません。それも良いと思うのですが、このセクションではinputタグ部分のみをコンポーネント化してみます。

やり方は、

  • inputタグをHiddenInputコンポーネントに外だしする。
  • refのコンポーネント間での受け渡しが発生するため、HiddenInputコンポーネントをforwardRef で囲み、外からrefを渡せるようにする。
  • inputタグのonChangeハンドラーもHiddenInputコンポーネントの外から渡せるようにする。

これで完成です。

豆知識

onChangeは連続で同じファイルを選択すると発火しない

二度同じファイルを選択したらonChangeは発火しないので注意してください。

状況としては、ファイルをstateで管理しているときに起こりえます。

  1. ファイルを選択、stateに保持。
  2. 先程のstateのファイルを削除
  3. もう一度同じファイルを選択 -> 何も起きない

試しに、以下で、ファイルを選択し、リセットボタン押して、もう一度同じファイルを選択してみてください。

以下のようにすると発火するようになります。

event.target.value = '';

Fileオブジェクトは列挙不可である

以下ができない

const a = JSON.stringify(file)
const b = {...file}

console.log(a)
console.log(b)

オブジェクトを拡張しながらコピーするやり方ができないので、何かしら対応方法を知っている方いましたら教えて下さい。

本当はこうやりたかった

const customFile = {...file, hoge: 'fuga'}

Discussion

ログインするとコメントできます