📂

[React]ファイル選択した画像を表示する(TypeScript)

2022/10/16に公開

はじめに

プロフィール画像を選択する時など、ローカルにある画像をReactで表示する際のやり方がわからなかったのでメモ

基本編: ファイル選択した画像を表示する

やり方

  • <input type="file" />でファイルを選択する
  • window.URL.createObjectURL()でオブジェクトURLを生成する
  • useState()<img src={xxx}>を更新する

実際のコード

inputonChangeでイベントを発火し、
選択されたファイルをwindow.URL.createObjectURL()に渡しています
※スタイルにはTailWind CSSを使用していますが、処理内容には影響しないため省略します

App.tsx
import React, { useState } from 'react';
import './App.css';

function App() {
  // useState()で画像のパスを保持
  // ※デフォルトで表示する画像を初期値で指定(この例ではpublicフォルダのdefault-profile.pngを指定)
  const [profileImage, setProfileImage] = useState('default-profile.png');

  const onFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (!e.target.files) return;

    // React.ChangeEvent<HTMLInputElement>よりファイルを取得
    const fileObject = e.target.files[0];
    // オブジェクトURLを生成し、useState()を更新
    setProfileImage(window.URL.createObjectURL(fileObject));
  };

  return (
    <div className="flex justify-center items-center mt-8">
      <img src={profileImage} className="h-32 w-32 rounded-full" />
      <input type="file" accept="image/*" onChange={onFileInputChange} className="pl-4" />
    </div>
  );
}

export default App;

実行結果


応用編: インプットボタンをカスタマイズする

デフォルトの「選択...」の部分をカスタマイズしていきます

やり方

  • useRef()<input />への参照を定義する
  • ボタンクリック時に、<input />の参照.current.click()でファイル選択のイベントを呼び出す
  • <input />onChange()の中でuseState()を更新する

カスタマイズ用のコード

useRef<HTMLInputElement>(null!);でinput属性への参照を定義し、
元々あった<input />hidden属性で隠しています
代わりに、ボタンクリック時にinputRef.current.click();でファイル選択のイベントを発火させています

App.tsx
import React, { useRef, useState } from 'react';
import './App.css';

function App() {
  const [profileImage, setProfileImage] = useState('default-profile.png');
  const inputRef = useRef<HTMLInputElement>(null!); // 追加

  // 追加
  const onProfileButtonClick = () => {
    // useRef<HTMLInputElement>のcurrent要素を呼び出し、ファイル選択画面を表示
    inputRef.current.click();
  };

  const onFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (!e.target.files) return;

    const fileObject = e.target.files[0];
    setProfileImage(window.URL.createObjectURL(fileObject));
  };

  return (
    <div className="flex justify-center items-center mt-8">
      <img src={profileImage} className="h-32 w-32 rounded-full" />
      {/* ref属性を指定し、hiddenで要素を隠す */}
      <input hidden ref={inputRef} type="file" accept="image/*" onChange={onFileInputChange} />
      {/* ファイル選択用のボタンを用意 */}
      <button
        className="bg-blue-500 text-white px-4 py-2 rounded-md ml-4"
        onClick={onProfileButtonClick}
      >
        プロフィール画像を選択
      </button>
    </div>
  );
}

export default App;

実行結果

参考

https://zenn.dev/tiwu_dev/articles/72f8d7de22b164
https://developer.mozilla.org/ja/docs/Web/API/URL/createObjectURL
https://zenn.dev/dove/articles/1927889e1c4153

Discussion