はじめに
タイトル通り。
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>
)
}
補足説明
-
画像アップロード機能について
- 「画像アップロード」ボタンを押すと、
emptytarget
とhandleFile
が起動する。 -
event.target.files[0]
で送信した画像データを取得できる。 - 変数
photo
に画像データを入れ、フォーム投稿時まで保持しておく。 - 画像はURLにしてimgタグでプレビュー表示する。そのため、
createObjectURL
によって、画像データを一意のURLに変換している。
- 「画像アップロード」ボタンを押すと、
-
画像投稿機能について
-
FormData
を使い、photo
で保持する画像データを送信するデータに付け加える。
-
参考