1
1

More than 1 year has passed since last update.

Reactで画像アップロード機能を作成する

Posted at

はじめに

タイトル通り。
reactとtypescriptで、投稿フォームに画像をアップロードする機能を実装したので、サンプルを掲載します。

仕様

  • 「画像アップロード」ボタンを押すと、ファイルエクスプローラーを開く。
  • 選択した画像がプレビュー表示される。
  • 「投稿する」ボタンを押すと、画像が保存される。←すなわち、画像を送信する際は二段階の手順を踏む必要がある。(「画像アップロード」ボタン→「投稿する」)「投稿する」ボタンを押しただけでは画像データを送信できないため、工夫が必要。(今回はFormDataを使用)
  • 画像アップロードをキャンセルできる。

結論のコード

Form.tsx
import React, { useState, useContext } from 'react'
import { useForm } from 'react-hook-form'

import { createPost } from '../../api/api_actions'
import { Post } from '../../interfaces/interface'

export const Form = () => {
  const { register, handleSubmit, formState: { errors } } = useForm<Post>()
  const [isFileTypeError, setIsFileTypeError] = useState<boolean>(false)
  const [photo, setPhoto] = useState<File>()
  const [preview, setPreview] = useState<string>("")

  const emptytarget: React.MouseEventHandler<HTMLInputElement> = (event) => {
    event.currentTarget.value = ''
  }

  const handleFile: React.ChangeEventHandler<HTMLInputElement> = async(event) => {
    if (event.target.files === null || event.target.files.length === 0) {
      return
    }
    setIsFileTypeError(false)

    const file = event.target.files[0]

    if (
      ![
        "image/jpeg",
        "image/png",
        "image/jpg"
      ].includes(file.type)
    ) {
      setIsFileTypeError(true)
      return
    }

    setPhoto(file)
    setPreview(window.URL.createObjectURL(file))
  }

  const onSubmit = async(data: Post) =>{

      const formData = new FormData()
      formData.append("post[image]", photo)

      try {
        const res = await createPost(formData as any)
        if (res.status === 200) {
          console.log('投稿に成功しました')
        } else {
          console.log(res.data.message)
        }
      } catch (err) {
        console.log(err)
      }
    }

  const canselFile = () => {
    setIsFileTypeError(false)
    setPhoto(undefined)
    setPreview("")
  }

  return(
    <div>
      <form onSubmit={handleSubmit(onSubmit)}>
          <p>画像</p>
          <p>ファイル形式はjpeg, png, jpgのみアップロード可能です。)</p>
          <label htmlFor="photo">
            画像アップロード
            <input hidden type="file" id="photo" name="photo" accept="image/*,.png,.jpg,.jpeg" onChange={handleFile} onClick={emptytarget}/>
          </label>

          {
            isFileTypeError && (
            <div>
              <span>jpeg, png, jpg以外のファイル形式は表示されません</span>
            </div>
          )}
              
          <br/>
          {
            preview ? (
              <div>
                <p>投稿画像イメージ</p>
                <img src={preview} alt="preview img" />
              </div>
            ) : (
              null
            )
          }
          <br/>
          <button type="submit">投稿する</button>
      </form>
      <button type="submit" onClick={canselFile}>画像リセット</button>
    </div>
  )
}

補足説明

  • 画像アップロード機能について

    • 「画像アップロード」ボタンを押すと、emptytargethandleFileが起動する。
    • event.target.files[0]で送信した画像データを取得できる。
    • 変数photoに画像データを入れ、フォーム投稿時まで保持しておく。
    • 画像はURLにしてimgタグでプレビュー表示する。そのため、createObjectURLによって、画像データを一意のURLに変換している。
  • 画像投稿機能について

    • FormDataを使い、photoで保持する画像データを送信するデータに付け加える。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1