6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Reactで画像アップローダーの作成

Last updated at Posted at 2023-12-11

はじめに

普段業務ではJavascript、Typescriptを用いたフロントエンドの画面ばかりを取り扱っているので、あまりバックエンドの機能に触れる機会がありませんでした。
なのでアプリの一つでも作ってみて勉強するべきだなぁと、普段から考えていました。


とはいっても作りたいものが特にないので、知り合いに聞いたところ「ファイルアップローダー」を自前で作れるようになるとフルスタックな知識が学べるようなので、今回は画像アップローダーを作成することにしました。

環境

React v18
express.js
multer

バックエンドはサーバーを借りて動かそうと思いましたが、無料で使えるよさげなのがなさそうなので(昔は色々あった気が...)止む無しでローカルに立ち上げます。

成果

nn00.PNG

画像を選択し、アップロードボタンを押すことで画像がサーバーへアップロードされます。

nn01.PNG

解説

特に複雑な事はしていないのですが、

frontend

フロントエンド部分はコンポーネントライブラリのMUIを使用してデザインしています。

    <div className="App">
      <Stack direction={"column"} sx={{ mt: 4, mb: 6 }}>
        <Box>
          <Button variant="contained" color="primary" component="label">
            <input accept="image/*" type="file" onChange={(e) => { setFile(e.target.files[0]); setFileName(e.target.files[0].name) }} style={{ display: 'none' }}/>
            画像を選択
          </Button>
          <Typography sx={{ mt: 2 }}>
            {fileName}
          </Typography>
        </Box>
        <Box sx={{ mt: 4 }}>
          <Button variant="outlined" type="button" onClick={upload} startIcon={<FileUploadIcon />} disabled={!file}>
            アップロード
          </Button>
        </Box>
      </Stack>
      <ImageList cols={3} rowHeight={200} sx={{ height: "700px" }}>
      {imgData && imgData.images.map((item) => (
        <ImageListItem key={item}>
          <img
            srcSet={`${imgUrl}${item}?w=164&h=164&fit=crop&auto=format&dpr=2 2x`}
            src={`${imgUrl}${item}?w=164&h=164&fit=crop&auto=format`}
            loading="lazy"
          />
        </ImageListItem>
      ))}
      </ImageList>
      
    </div>

backend

バックエンドでは、API "/upload"でファイルの送信リクエストを受け取りストレージに保存し、"/images"で保存されているファイル名一覧を取得して送り返しています。

const express = require("express")
const cors = require("cors")
const multer = require("multer")
const fs = require('fs');
const path = require('path');

const port = 3001
const app = express()
app.use(cors())
app.use(express.json())
app.use('/img', express.static(__dirname + '/public/Files'))

const storage = multer.diskStorage({
	destination: function(req, file, cb) {
		return cb(null, "./public/Files")
	},
	filename: function(req, file, cb) {
		return cb(null, `${Date.now()}_${file.originalname}`)
	}
})

const upload = multer({storage, fileFilter: (req, file, cb) => {
	if(file.mimetype.includes("image")) {
		cb(null, true);
		return;
	}
	cb(new TypeError("Invalid File Type"));
}})

app.post("/upload", upload.single("file"), (req, res) => {
	console.log(req.body)
	console.log(req.file)
	res.status(200).send("uploaded")
})

app.get("/images", (req, res) => {
	fs.readdir("./public/Files", (err, files) => {
		if (err) {
			console.error('Error reading directory:', err);
			return res.status(500).json({ error: 'Failed to read directory' });
		}
	
		// ファイルを画像ファイルにフィルタリング
		const imageFiles = files.filter(file => {
			const ext = path.extname(file).toLowerCase();
			return ext === '.png' || ext === '.jpg' || ext === '.jpeg' || ext === '.gif';
		});
	
		res.status(200).json({ images: imageFiles });
	});
})

app.listen(port, () => {
	console.log("Server is running")
})

Github https://github.com/gigadeli/prac_img_uploader

おわりに

バックエンドはローカル環境かつ、expressで作成したので、当たり前ですが難易度は高くなかったです。
もっとこうDBを用意してCRUD機能も付けて... でやりたかったのですが
多分作りきる前に燃え尽きるので、今回はやりきることを目標にしました:sunrise:

6
0
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
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?