📑

React.jsでの画像アップロードからプレビュー表示

2022/12/01に公開

はじめに

React.jsを使って、画像アップロードからプレビュー表示までを作成していきます。

Reactとは

https://ja.reactjs.org/

環境

Windows 10
Node.js 8.5.5
React.js

フォルダ構成

react
├── node_modules
├── public
│ └── index.html
├── src
│ ├── index.js
│ └── index.css
└── package.json

レイアウト作成

まずは、react/src/index.jsの中身を次のようにします。

import { createRoot } from 'react-dom/client'
import React, { Component } from 'react'

export default class App extends React.Component {
    render() {
        return (
            <div>
                <input type="file" accept="image/*" />
                <div>
                    <img src="" />
                </div>
            </div>
        )
    }
}

const root = createRoot(document.getElementById('app'))
root.render(<App />)

<input type="file">の下にプレビュー表示できる要素を設置します。

呼出側のHTMLreact/public/index.htmlの記載は以下です。

<html>
<body>
    <div id="app"></div>
</body>
</html>

React.jsの作成

次にReact.js部分です。

コンストラクタで画像を格納する変数の準備

Appが呼び出された直後にthis.stateへ変数名imageDataを作ります。
ここには<input type="file">で選択された画像データが入ってきます。

constructor(props) {
    super(props)
    this.state = {
        imageData: null
    }
}

画像選択時のイベントを作成

<input type="file">onChangeイベントを設定します。
その際、onFileChange()にイベント変数を渡します。

return (
    <div>
        <input type="file" accept="image/*" onChange={
            (e) => {
                this.onFileChange(e)
            }
        } />
        <div>
            <img src="" />
        </div>
    </div>
)

イベント変数を受け取るonFileChange()は以下で作成します。
画像が選択されていた場合、FileReader()で画像データを取得しています。

取得した画像データは、先ほど記載したconstructorで設定したimageDataの変数に格納しています。

もし、キャンセルされた場合は、imageDatanullを渡し、初期化をしています。

onFileChange(e) {
    const files = e.target.files
    if (files.length > 0) {
        var file = files[0]
        var reader = new FileReader()
        reader.onload = (e) => {
            this.setState({ imageData: e.target.result })
        };
        reader.readAsDataURL(file)
    } else {
        this.setState({ imageData: null })
    }
}

プレビュー表示箇所の作成

preview変数に画像要素を格納することで、画像が選択されていない場合に何も表示せず、画像が選択された場合にのみ、プレビュー要素を表示することができます。

render() {
    const imageData = this.state.imageData
    let preview = ''

    if (imageData != null) {
        preview = (
            <div>
                <img src={imageData}/>
            </div>
        )
    }

    return (
        <div>
            <input type="file" accept="image/*" onChange={
                (e) => {
                    this.onFileChange(e)
                }
            } />
            {preview}
        </div>
    )
}

最終的なindex.js

import { createRoot } from 'react-dom/client'
import React, { Component } from 'react'

export default class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            imageData: null
        }
    }

    onFileChange(e) {
        const files = e.target.files
        if (files.length > 0) {
            var file = files[0]
            var reader = new FileReader()
            reader.onload = (e) => {
                this.setState({ imageData: e.target.result })
            };
            reader.readAsDataURL(file)
        } else {
            this.setState({ imageData: null })
        }
    }

    render() {
        const imageData = this.state.imageData
        let preview = ''

        if (imageData != null) {
            preview = (
                <div>
                    <img src={imageData}/>
                </div>
            )
        }

        return (
            <div>
                <input type="file" accept="image/*" onChange={
                    (e) => {
                        this.onFileChange(e)
                    }
                } />
                {preview}
            </div>
        )
    }
}

const root = createRoot(document.getElementById('app'))
root.render(<App />)

実行結果

おわりに

React.jsはパーツごとの実装に長けているので、他にも応用できれば、可読性の高い良いプロジェクトが作れそうな感じはしました。
(書き方については慣れが必要かもしれません。)

以上、React.jsでの画像アップロードからプレビュー表示までの実装でした。

Discussion