2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

「Authentication App」作成記録 - React + Firebaseで作るWebシステムの認証機能

Posted at

「Authentication App」作成記録 - React + Firebaseで作るWebシステムの認証機能

devchallengesの「Authentication App」に取り組んだ記録です。

devchallenges

devchallengesは、様々なソフトウェアのお題を提供してくれるサイトです。お題には、そのソフトウェアが満たすべきユーザーストーリーと、画面イメージが記載されています。何を作るかは説明がありますが、どう作るかは基本的に書いていないため、アプリケーション開発の学習に最適です。

今回は、Authentication Appというお題に取り組みました。

何を作ったか?

認証機能を持つWebアプリケーションを作成しました。下記の機能があります。

  • 認証機能。予めメールアドレスとパスワードを登録しておき、それでログインできます。
  • SNS認証機能。Googleアカウントを使用してログインできます。Twitter等もできるようにしたかったのですが、Twitter側でのApp登録が面倒で諦めました。。。
  • プロフィール編集機能。ユーザーの名前、アバター画像などが編集できます。

また、一応レスポンシブ対応しているので、スマホで見ることもできます。
(ちょっとトップ画面が崩れてますが…(汗))

リポジトリ・デモ

成果物は下記のリポジトリにコミットしています。使い方はREADME.mdを参照してください。

また、作成したアプリケーションはデプロイしています。下記のURLからお試しできます。

画面紹介

  • ログイン画面

login.png

  • トップ画面

userinfo.png

  • 編集画面

userinfoedit.png

React部品紹介

作成したReact部品のうち、他のアプリにも流用できそうな部品を紹介します。

Auth.tsx

今回のアプリで一番頑張った部品です。React-Router-Domと組み合わせることで、認証に関するロジックをすべてここへと集約しています。

基本的なつくり・アイデアは、こちらの記事を参考にしました。これをFirebase/Redux用に少しカスタマイズしています。

https://qiita.com/ginban22/items/a36d01b41deaeedd581e

この部品は、下記のように利用します。認証が必要な画面へのRouteはAuthコンポーネントのchildrenに指定します。必要ない画面へのRouteはAuthコンポーネントの外に指定します。すると、firebase上で認証済みの場合は各画面を表示し、未認証状態の場合はloginUriで指定した画面(下の場合はLoginコンポーネント)を表示します。

AppRouter.tsx
      <Router>
        <Switch>
          <Route exact path={pathLogin} component={Login} />
          <Route exact path={pathSignUp} component={SignUp} />
          <Auth loginUri={pathLogin} loadingComponent={LoginLoading}>
            <Switch>
              <Route exact path={pathUserInfoEdit} component={UserInfoEdit} />
              <Route component={UserInfo} />
            </Switch>
          </Auth>
        </Switch>
      </Router>

AvatarEdit.tsx

画像をアップロードするための部品です。アップロードすると、Avatarタグにプレビュー表示します。プロフィールの編集画面で利用しています。

どうやって作ったか?

Webアプリケーションの中身や、作成時に調べたことをまとめています。

採用した技術/ライブラリ

  • React
    • SPAフレームワークとして採用。Vueよりも単純に好き。
  • TypeScript
    • 型付けできるTypeScriptを採用。
  • Firebase
    • バックエンド。ホスティング・アップロードデータの保存に利用。
  • Material-UI
    • 画面のUI用ライブラリ。
  • React Redux
    • 状態管理用のライブラリ。
  • React Router Dom
    • ルーティングのライブラリ。

デザイン

Material-UIでCSSセレクタのhoverやnth-of-typeを使う

Material-UIではcss-in-javascriptを採用しているため、直接CSSセレクタを使うことはありません。しかし、Material-UI側でちゃんと用意してくれています。

画像ボタンの作り方

CSSを使うと、画像をボタンのように見せかけることができます。本アプリでは、ログイン画面のSNS認証のところで使ってます。

material-UI Grid itemの中央寄せ

レスポンシブ対応

入門的な内容ですが、今の自分にはこれで十分でした。

複数のクラス名を結合する・動的なクラス名の指定

clsxというライブラリが、Material-UIにくっついてきます。これを使うと楽でした。また、clsxを使うと動的にクラスを切り替えることができます。

Webアプリ

textFieldでEnterが押されたときにイベントを実行する

onKeyDownイベントを使うとできます。イベントハンドラーのKeyプロパティで押されたキーを判別します。
検索するとKeyCodeを使うサンプルが多いですが、これは非推奨でWeb標準から削除されています。

画像ファイルのプレビュー表示

Javascriptに標準でついているFileReader APIが使えます。

複数の非同期処理

Firebaseへのアップロード処理を非同期で行いますが、最大で4つのPromiseを並列実行しました。4つの処理を並列実行し、それらがすべて終わった後でやりたい処理があるときは、標準で用意されているPromise.allが使えます。

FirebaseのAPI

今回利用したFirebaseの各機能の使い方をまとめます。(後で自分が使うとき思い出せるように…)

事前準備

どのFirebase Projectのアプリケーションなのか、コード上で設定する必要があります。下記参照。

auth:サインイン

let promise: Promise<firebase.auth.UserCredential>;
// メールアドレス & Passwordの場合
promise = firebase.auth().signInWithEmailAndPassword(mail, password);
// Google認証の場合
promise = firebase.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider());
// 認証後の後処理
promise.then((userCredential) => {
  const user = credential.user;
  if(user){
    const {displayName, email, phoneNumber, photoURL, uid} = user; // この辺のプロパティが利用できます。
  }
}).catch((error) => {
  const { code, message } = error; // この辺のプロパティが利用できます。
});

auth:サインアップ

firebase.auth().createUserWithEmailAndPassword(mail, password).then((userCredential) => {
  const user = credential.user;
  if(user){
    const {displayName, email, phoneNumber, photoURL, uid} = user; // この辺のプロパティが利用できます。
  }
}).catch((error) => {
  const { code, message } = error; // この辺のプロパティが利用できます。
});

auth:認証状態のオブザーバーを設定する

firebase.auth().onAuthStateChanged((user) => {
  if (user) {
    // User is signed in, see docs for a list of available properties
    // https://firebase.google.com/docs/reference/js/firebase.User
    const {displayName, email, phoneNumber, photoURL, uid} = user; // この辺のプロパティが利用できます。
  } else {
    // User is signed out
  }
}).catch((error) => {
  const { code, message } = error; // この辺のプロパティが利用できます。
});

auth:サインアウト

firebase.auth().signOut().then(() => {
  // サインアウト成功時
}).catch((error) => {
  const { code, message } = error; // この辺のプロパティが利用できます。
});

firestore:オブザーバーを設定してデータを取得する

firebase.firestore().collection('CollectionName').doc('id').onSnapshot(
  (snapshot) => {
    if(snapshot.exists){
      const fieldValue = snapshot.get('FieldName');
    }
  },
  (error) => {}
);
  • RDBとFirestoreのイメージ対応(個人の感想)
Firestore RDB
collection table
doc record
field column

firestore:データを保存する

firebase.firestore().collection('CollectionName').doc('id').set({
  field1: 'field1',
  field2: 'field2'
})
  • 補足:setを使うと、ドキュメントがなければ作成し、ドキュメントがあれば上書き更新する。他にもupdate等があり、挙動が若干違う。

storage:ファイルをアップロードする

firebase.storage().ref().child('親フォルダ').child('子フォルダ').child('ファイル名').put(file).then((snapshot) => {
  const url = await snapshot.ref.getDownloadURL(); // ファイルのURL。
})
2
2
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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?