ReactApps

2019年3月9日

画像ファイルを選択してプレビューを表示する

dahmz22fa

はじめに

ローカル環境でこのサンプルを動かすには以下の手順に従ってください。

$ git close git@github.com:reiwa/reactapps.git
$ cd reactapps
$ yarn
$ yarn workspace file start

※ $の部分はペーストしないでください。

内容

ユーザは画像ファイルを選択しプレビューを表示します。
画像をファイルをアップロードする前にプレビューを表示することができます。

コード

import React, {
  Fragment,
  FunctionComponent,
  useState,
  createRef,
  ChangeEvent,
} from 'react'

const App: FunctionComponent = () => {
  const [src, setSrc] = useState('')
  const ref = createRef<HTMLInputElement>()
  const onClick = () => {
    if (ref.current) {
      ref.current.click()
    }
  }
  const onChange = (event: ChangeEvent<HTMLInputElement>) => {
    if (event.target.files === null) {
      return
    }
    const file = event.target.files.item(0)
    if (file === null) {
      return
    }
    var reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = () => {
      setSrc(reader.result as string)
    }
  }

  return (
    <Fragment>
      <input
        onChange={onChange}
        ref={ref}
        style={{ display: 'none' }}
        type={'file'}
      />
      <button onClick={onClick}>file</button>
      <div>{src && <img src={src} />}</div>
    </Fragment>
  )
}

export default App

いくつかポイント

このコンポーネントはプレビューのアドレスを状態(State)として扱います。

const [src, setSrc] = useState('')

UIを書き換え易くする為に`input`ではなく`button`を用いています。
`createRef`を用いて`button`の`onClick`から`input`のクリックイベントを発火するようにします。

const ref = createRef<HTMLInputElement>()

return (
    <Fragment>
      <input
        onChange={onChange}
        ref={ref}
        style={{ display: 'none' }}
        type={'file'}
      />
      <button onClick={onClick}>file</button>
      <div>{src && <img src={src} />}</div>
    </Fragment>
  )

`onClick`ではクリックイベントを呼び出すだけです。

const onClick = () => {
  if (ref.current) {
    ref.current.click()
  }
}

`onChange`関数では選択したファイルからプレビューのアドレスを作成し`setSrc`を用いて`src`を更新します。

const onChange = (event: ChangeEvent<HTMLInputElement>) => {
  if (event.target.files === null) {
    return
  }
  const file = event.target.files.item(0)
  if (file === null) {
    return
  }
  var reader = new FileReader()
  reader.readAsDataURL(file)
  reader.onload = () => {
    setSrc(reader.result as string)
  }
}

`setSrc`の呼び出しは非同期なので、実際にはライフサイクルには注意する必要があります。