React と Firebase でブログサービス〜ファイルのアップロード編

記事
IT・テクノロジー

React と Firebase でブログサービス〜ファイルのアップロード編

React と Firebase を組み合わせて利用する例として、ブログサービスを作ってみる事にしました。一度に全部紹介するのは難しいので連載という形で紹介していきます。最初は、ブログの記事をインターネット上にアップロードする機能から紹介していきます。


まず最初は投稿の機能

ブログサービスで必要になる機能に、記事を投稿する機能が必要になります。 今回は、ブログの記事の原稿となるファイルをインターネットにアップロードする機能について紹介します。 Firebase を利用する場合、データベースに記事を保存する方法もありますが、今回は記事の原稿のファイルそのものを Firebase のストレージに保存する方法を採用しようと考えています。

どのようなファイルをブログの原稿にするかを決める必要がありますが、まずは、ファイルを Firebase のストレージに保存する機能が必要です。この記事では、Firebase のストレージにファイルを指定したファイルをアップロードする機能について考えてみました。

ファイルの指定

まずは、アップロードするファイルを選択する機能が必要です。 ファイルを選択するフォームを作成します。

HTML の「input」タグを使ってファイルを選択して、ファイルをアップロードする処理を呼び出すような UI です。 ファイルは、Firebase ストレージの「test」というフォルダの下にアップロードするようになっています。

(post.tsx)の例

export default () => {
  return (
    <React.Fragment>
      <div>
        <h1>Post</h1>
        <form className="form-group">
          <label>ブログの原稿</label>
          <input
            className="form-control"
            type="file"
            onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
              fileSelectedEvent(e)
            }
          />
        </form>
      </div>
    </React.Fragment>
  );
};
function fileSelectedEvent(e: React.ChangeEvent<HTMLInputElement>) {
  if (e.target.files && e.target.files[0]) {
    const file: File = e.target.files[0];
    uploadFile("test", file).then((result: boolean) => {
      if (result) {
        alert(file.name + " is uploaded.");
      } else {
        alert("Upload is failed");
      }
    });
  }
}

ファイルのアップロード

アップロードするブログの原稿が選択された後は、そのファイルを Firebase のストレージにアップロードして保存します。 Firebase のドキュメントを参考に以下のような関数を作成します。アップロードが成功した場合は、「true」をアップロードが失敗した場合には、「false」を返します。

import firebase from "./firebase";
const DEBUG: boolean = true;
export function uploadFile(path: string, file: File): Promise<boolean> {
  return new Promise((resolve) => {
    const storageRef: firebase.storage.Reference = firebase
      .storage()
      .ref()
      .child(path + "/" + file.name);
    const uploadTask: firebase.storage.UploadTask = storageRef.put(file);
    uploadTask.on(
      "state_changed",
      (snapshot: firebase.storage.UploadTaskSnapshot) => {
        const progress =
          (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
        if (DEBUG) {
          console.log("Upload is " + progress + " % done");
        }
        switch (snapshot.state) {
          case firebase.storage.TaskState.PAUSED: // or 'paused'
            console.log("Upload is paused");
            break;
          case firebase.storage.TaskState.RUNNING: // or 'running'
            console.log("Upload is running");
            break;
        }
      },
      (error: any) => {
        if (DEBUG) {
          console.log(error.message);
        }
        // Error
        resolve(false);
      },
      () => {
        // Normal completion
        resolve(true);
      }
    );
  });
}

Firebase の機能を利用するには、Firebase の初期化が必要です。

(firebase.ts)の例 Firebase のプロジェクト情報は、プロジェクトフォルダの「.env」で設定します。 こうすることで、別の Firebase のプロジェクトで同じプログラムを利用する場合でもプログラムに変更を加える必要がなくなります。 Firebase のプロジェクト情報は、Firebase コンソールに行くと取得できます。

import firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
import "firebase/storage";
import "firebase/analytics";
// Your web app's Firebase configuration
const firebaseConfig = {
  apiKey: process.env.REACT_APP_apiKey ? process.env.REACT_APP_apiKey : "",
  authDomain: process.env.REACT_APP_authDomain
    ? process.env.REACT_APP_authDomain
    : "",
  databaseURL: process.env.REACT_APP_databaseURL
    ? process.env.REACT_APP_databaseURL
    : "",
  projectId: process.env.REACT_APP_projectId
    ? process.env.REACT_APP_projectId
    : "",
  storageBucket: process.env.REACT_APP_storageBucket
    ? process.env.REACT_APP_storageBucket
    : "",
  messagingSenderId: process.env.REACT_APP_messagingSenderId
    ? process.env.REACT_APP_messagingSenderId
    : "",
  appId: process.env.REACT_APP_appId ? process.env.REACT_APP_appId : "",
  measurementId: process.env.REACT_APP_measurementId
    ? process.env.REACT_APP_measurementId
    : "",
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
export default firebase;

Firebase のセキュリティルールが必要です

Firebase のストレージにブログの原稿を保存する場合、Firebase のセキュリティルールを設定する必要があります。

ブログサービスの場合、ブログの執筆者のみがファイルをアップロードするのが普通ですので、実際にはユーザー認証をして執筆者と特定された場合のみ許可するルールが必要です。今回は、ファイルのアップロードの紹介なので、簡易的なセキュリティルールで取り敢えず誰でもファイルをアップロードできるようなルールを設定しました。将来の記事でセキュリティルールは修正します。 インターネットに公開する場合には注意が必要です!

(*)以下のセキュリティルールの場合、誰でも「test」フォルダにファイルを読み書きできる設置になっています。

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /test {
        match /{allPaths=**} {
          allow read, write;

      }
    }
  }
}
これで、選択したファイルを Firebase のストレージにアップできるようになります。

まとめ

この記事では、ブログサービスの基本機能の一つである、ブログの記事の原稿のファイルを Firebase のストレージにアップロードする方法を紹介しました。

ポイントは:

1. ファイル選択フォームの作成(UI)
2. Firebase の初期化
3. ファイルをアップロードする関数の作成
これで、ファイルが選択されたのを検出して、ファイルをアップロードする関数を呼び出すだけです。

Firebase を利用するとシンプルな処理で、Firebase のストレージに原稿を保存できます。

これで、ブログの投稿に必要な最低限の機能は実現できます。

次回は、ファイルの一覧を表示できるようにします!お楽しみに!
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す