📷

【Next.js × Firebase】Storageで簡単画像アップロード

2024/06/23に公開

はじめに

今までにFIrebaseのサービスであるAuthenticationやFirestoreを紹介してきました。
今回はその第三弾でStorageサービスを利用した画像アップロードを紹介しようと思います。
今までの記事はこちらです!
https://zenn.dev/kiwichan101kg/articles/ee5460b61bce25
https://zenn.dev/kiwichan101kg/articles/b38dd43d04622e

Firebaseセットアップ

前回の記事で紹介したので省略します。

Strageセットアップ

Strage>始める

セキュリティルールの設定(本番環境を潜ったくしました)

ロケーションの設定(わたしは元々設定してありましたがアジアでテキトーに)

完了!

Firebase+Storage初期化処理

Next.jsの記述に移ります。

config情報はfirebaaseのプロジェクトの設定に記載されているものを環境変数で管理しています。
設定の場所については前回の記事を参考にしてください。
getStorageをimportしてappを引数にいれたものをexportします。

import { initializeApp } from "firebase/app";
import { GoogleAuthProvider, getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
+ import { getStorage } from "firebase/storage";


// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: process.env.FIREBASE_APIKEY,
  authDomain: process.env.FIREBASE_AUTH_DOMAIN,
  projectId: process.env.FIREBASE_PROJECT_ID,
  storageBucket: process.env.FIREBASE_STRAGE_BUCKET,
  messagingSenderId: process.env.FIREBASE_MASSAGING_SENDER_ID,
  appId: process.env.FIREBASE_APP_ID,
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
// Initialize Cloud Firestore and get a reference to the service
export const auth = getAuth(app);
export const db = getFirestore(app);
+ export const storage = getStorage(app);
export const provider = new GoogleAuthProvider();

画像アップロードコンポーネント作成

画像アップロードコンポーネントのUIを作成します。
input要素のtype=fileで作成します。
accept属性で受け入れる拡張子を指定します。
https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/accept

また、複数ファイル選択できるようmultiple属性も付与します。

FileUploader.tsx
export const FileUploader = ({ setImage }: FileUploaderProps) => {
// ファイルアップロード処理
const onFileUpload = () => {}

  return (
    <div>
      <input
        type="file"
        onChange={onFileUpload}
        multiple
        accept=".png,.jpeg,.jpg"
      />
    </div>
  );
};

続いてはonChange属性に渡している、画像がアップロードされた際の関数の中身を記述していきます。

初期化処理でexportしたstorageと以下をfirebase/storageからimportして使用します。

import { storage } from "@/lib/firebase/firebase";
import { getDownloadURL, ref, uploadBytes } from "firebase/storage";

ref

refはfirebaseのStorageのどこにアップロードするかを指定します。

image/ファイル名.pngになるよう保存場所を指定しました。

const storageRef = ref(storage, `image/${file.name}`);

uploadBytes

uploadBytesでfirebaseのStorageにアップロードします。

const snapshot = await uploadBytes(storageRef, file);
console.log("Uploaded a blob or file!", snapshot);

getDownloadURL

アップロードに成功したらgetDownloadURLで画像のurlを取得し、画面側に表示させます。
useStateでsetImagesに複数画像urlを保持し、表示させるようにしています。

const url = await getDownloadURL(storageRef);

全体の実装はこちらです。
複数画像のアップロードに対応するためアップロード処理をループさせます。

FileUploader.tsx
  const onFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    if (!e.target.files) return;
    const files = e.target.files;
    if (files.length < 1) return;
    
    const urls: string[] = [];
    for (let i = 0; i < files.length; i++) {
      const file = files[i];
      const storageRef = ref(storage, `image/${file.name}`);

      try {
        const snapshot = await uploadBytes(storageRef, file);
        console.log("Uploaded a blob or file!", snapshot);
        try {
          const url = await getDownloadURL(storageRef);
          urls.push(url);
        } catch (urlError) {
          console.error("Error getting download URL:", urlError);
        }
      } catch (uploadError) {
        console.error("Error uploading file:", uploadError);
      }
    }

    setImages(urls);
  };

画像アップロードしてみる

ファイル選択押下して画像を選択します。

アップロードした画像が表示されました!

Firebaseを確認してみるとアップロードされていそうです。

おまけ

権限エラーが発生【解決】

最初uploadしたところエラーが発生しました。
FirebaseError: Firebase Storage: User does not have permission to access 'image/スクリーンショット 2024-06-16 17.22.15.png'. (storage/unauthorized)

Storageのルールを変更します。

読み書きできない状態から誰でも読み書きできる状態に。

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
-      allow read, write: if false;
+      allow read, write: if true;
    }
  }
}

まとめ

今回はFirebaseのサービス第三弾Storageを紹介しました!
少しでも参考になれば嬉しいです!
AuthenticationやFirestoreの実装例についても解説しているのでぜひ!
https://zenn.dev/kiwichan101kg/articles/ee5460b61bce25
https://zenn.dev/kiwichan101kg/articles/b38dd43d04622e

Discussion