20190512のReactに関する記事は3件です。

React+Redux+TypescriptでFirebaseのLogin機能を実装する

最近Reactをよく触ってて、その際にReactからFirebase Loginを実装する方法について学んだのでその知見を書きます。
Firebase Login機能のサンプルコードはこちらに置いてあります。

実装ではなるべくモダンな開発環境で使われてそうなライブラリを使いたかったのでReact、Redux、Typescriptを使っています。
ESLintやPretter、lint-stagedの設定もなるべく追加するようにしています。
また、Reactコンポーネントはクラスを使って実装するのではなく、ここではなるべく関数コンポーネントを使って書くようにしてます。

アプリの概要

見た目はログイン機能を検証する上で必要最小限にしています。
スクリーンショット 2019-05-11 18.18.50.png

Google Loginボタンを押すとGoogleのログイン認証ページにリダイレクトして認証をします。
ユーザ認証が成功するとguestの部分がユーザ名に、ボタンの名前はGoogle Logoutに変わります。

Presentational ComponentとContainer Component

見た目の部分はcomponents/Auth.tsxで実装しています。
描画する際に必要なプロパティはAuthPropsで定義しています。

components/Auth.tsx
import React, { FC } from 'react';
import firebase from '../config/index';

interface AuthProps {
  loginUser?: firebase.User | null;
  handleLogin?: () => void;
  handleLogout?: () => void;
}

const AuthComponent: FC<AuthProps> = props => {
  const { loginUser, handleLogin, handleLogout } = props;

  return (
    <>
      {loginUser ? (
        <>
          <p>{loginUser.displayName}さんこんにちは</p>
          <button type="button" onClick={handleLogout}>
            Google Logout
          </button>
        </>
      ) : (
        <>
          <p>guestさんこんにちは</p>
          <button type="button" onClick={handleLogin}>
            Google Login
          </button>
        </>
      )}
    </>
  );
};

export default AuthComponent;

AuthComponentでは表示に必要な値をprops経由で受け取っている。
ログイン情報などの実体はcontainers/Auth.tsxの方で持っていて、HOCを使用してprops経由でコンポーネントに値を渡しています。
実際に値の渡している部分とHOCを使っている部分は以下の通りです。

containers/Auth.tsx
const AuthContainer: FC<AuthState & DispatchProps> = ({
  loginUser,
  dispatchAuthStatus,
  handleLogin,
  handleLogout,
}) => {
  firebase.auth().onAuthStateChanged(user => {
    dispatchAuthStatus(user);
  });

  return (
    <AuthComponent
      loginUser={loginUser}
      handleLogin={handleLogin}
      handleLogout={handleLogout}
    />
  );
};

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(AuthContainer);

HOCを利用することでPresentational ComponentとContainer Componentを分離することができ、上記のコードではAuthComponentをAuthContainerでラップしています。
export default connect(...の処理でreduxのstoreと接続したコンポーネントを生成して、これがApp.tsxのrenderで使われます。
コンポーネントに渡すStateとdispachはそれぞれmapStateToProps、mapDispatchToPropsとして定義しています。

containers/Auth.tsx
import { AuthState, changeAuthStatus } from '../reducers/auth';

...

const mapStateToProps = (state: ApplicationState): AuthState => ({
  loginUser: state.auth.loginUser,
});

export interface DispatchProps {
  dispatchAuthStatus: (user: firebase.User | null) => void;
  handleLogout: () => void;
  handleLogin: () => void;
}

const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
  dispatchAuthStatus: (user: firebase.User | null) =>
    dispatch(changeAuthStatus(user)),
  handleLogout: () => {
    firebase.auth().signOut();
    dispatch(changeAuthStatus(null));
  },
  handleLogin: () => {
    const user = firebase.auth().currentUser;
    if (!user) {
      const provider = new firebase.auth.GoogleAuthProvider();
      firebase.auth().signInWithRedirect(provider);
    } else {
      dispatch(changeAuthStatus(firebase.auth().currentUser));
    }
  },
});

Reducerを通した状態遷移

このアプリではユーザのログイン情報をStateとして保持し、StateをReduxを使って管理します。
Reduxを使った状態管理を実現するためにはActionType、ActionCreater、Reducerを実装する必要があります。
実装方法のプラクティスはいくつかあるのですが、このアプリではファイル分割がほとんど必要ないducksパターンを採用します。
Reducerなどを実装したファイルはreducers/配下に配置していて、Reducerのrootとなる部分はreduckers/index.tsで定義しています。

reducers/index.ts
const reducers: Reducer<ApplicationState> = combineReducers<ApplicationState>({
  auth,
});

export default reducers;

combineReducersは指定したreducerを統合したreducerの状態ツリーを作成します。
作成されたreducerはindex.tsx内のcreateStoreの引数として渡します。

index.tsx
import reducers from './reducers/index';

...

const store = createStore(reducers, enhancer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root'),
);

combineReducersにはオブジェクトを渡すだけなので今後reducerが増えたとしても拡張は容易です。今回はreducers/auth.tsから読み込んだreducerのみ追加しています。
auth.tsのreducerではユーザ情報を管理したいのでfirebaseから受け取った認証情報がdispatchされたら新しくstateを更新するようにします。

reducers/auth.ts
// actionType
export const CHANGE_AUTH_STATUS = 'USER/CHANGE_AUTH_STATUS';

// actionCreater
export const changeAuthStatus = (user: firebase.User | null) => ({
  type: CHANGE_AUTH_STATUS as typeof CHANGE_AUTH_STATUS,
  user,
});

// reducer
const auth: Reducer<AuthState, AuthAction> = (
  state: AuthState = initialState,
  action: AuthAction,
) => {
  switch (action.type) {
    case CHANGE_AUTH_STATUS:
      return {
        ...state,
        loginUser: action.user,
      };
    default:
      return state;
  }
};

補足

Firebaseの設定

githubには挙げていないですが、Firebaseの設定ファイルはこんな感じにしてます。

config/config.js
export const firebaseConfig = {
  apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  authDomain: 'sample-project.firebaseapp.com',
  projectId: 'sample-project',
  messagingSenderId: '111111111111',
};

参考文献

りあクト! TypeScriptで始めるつらくないReact開発 第2版
りあクト! TypeScriptで極める現場のReact開発
https://medium.freecodecamp.org/how-to-build-a-chat-application-using-react-redux-redux-saga-and-web-sockets-47423e4bc21a
https://medium.com/@resir014/a-type-safe-approach-to-redux-stores-in-typescript-6474e012b81e
JavaScript による Google ログインを使用した認証

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Firebaseを使ってReactの認証処理をあっという間に完成させる

手順

  • プロジェクトを作成する
  • アプリを追加する
  • firebase.jsの作成
  • ログイン処理の実装

プロジェクトを作成する

プロジェクトの作成は、Firebaseのトップページから簡単な設定で完了することができます。

アプリを追加する

プロジェクトのトップからアプリを追加するとFirebase SDKの必要な情報を取得することができます。

firebase.jsの作成

Firebase SDKの情報が取得できたら、Firebase Authentificationを利用するためにfirebase.jsを作成します。

コードは下記の通り。

firebase.js
import firebase from "firebase";
import "firebase/auth";

const firebaseConfig = {
  apiKey: ***,
  authDomain: ***,
  databaseURL: ***,
  projectId: ***,
  storageBucket: ***,
  messagingSenderId: ***,
  appId: ***
};

firebase.initializeApp(firebaseConfig);

export default firebase;

ログイン処理の実装

ログイン処理を実装するにあたり、必要な要素は下記の通り

  • サインアップ処理
  • ログイン処理
  • ユーザーがログイン済みかどうかのチェック
  • ユーザー情報の取得

では、それぞれのコードをご説明します。

ユーザーがログイン済みかどうかのチェック

ユーザーがログイン済みかどうかチェックするためのコードは下記の通り。サービスのルートに近いファイル(create-react-appであればApp.js)などで一度これを実行すれば問題ないです。

App.js
firebase.auth().onAuthStateChanged(user => {
    this.setState({ user })
})

ログイン処理

ログイン処理を行うためには、signInWithEmailAndPassword関数を使用します。

firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
  // Handle Errors here.
  var errorCode = error.code;
  var errorMessage = error.message;
  // ...
});

サインアップ処理

ログイン処理と似ていますが、サインアップ処理を行う場合はfirebase.auth()のcreateUserWithEmailAndPassword関数を使います。

firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
  // Handle Errors here.
  var errorCode = error.code;
  var errorMessage = error.message;
  // ...
});

これでログイン処理とサインアップ処理が完了しました。あとは、ログインとサインアップの画面を作成してそれぞれの処理を行うようにすればOKですね。

ユーザー情報の取得

あとはユーザー情報を取得すれば、任意のユーザーを認識することが可能になります。

ユーザー情報の取得は、下記のコードで取得することができます。

var user = firebase.auth().currentUser;
var name, email, photoUrl, uid, emailVerified;

if (user != null) {
  name = user.displayName;
  email = user.email;
  photoUrl = user.photoURL;
  emailVerified = user.emailVerified;
  uid = user.uid;  // The user's ID, unique to the Firebase project. Do NOT use
                   // this value to authenticate with your backend server, if
                   // you have one. Use User.getToken() instead.
}

uidは、ユーザーを一意に認証するためのidとして使用することができます。

また、Cloud Firestoreなどのデータベースを使用する場合も、個人に紐付いた情報はuidを使って管理する方法が一般的です。

参考

Firebase でユーザーを管理する
https://firebase.google.com/docs/auth/web/manage-users?hl=ja

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OSSで政治系のことについて議論できるChatスペースを作りたい

課題

日本ではSNSで政治のことは呟かれない

日本人は周りの人に合わせる癖があるので、SNSの投稿は基本的にキラキラしたものが多いです。自分がキラキラした生活を送っていることを投稿すればするほど、みんなからのいいねがたくさん来たり、みんなと同じような投稿をしたりすると共感が得られるシステム、それがSNSです。だからいつもSNSでフォロワーの多い人や友達のツイートを見て、同じような投稿をし、共感をえて、いいねをもらう。一つのゲームみたいなもので、ポケモンGOとかとあまり変わりありません。
キラキラしたものをinstagramに載せるのが悪いと言ってる訳ではなく、社会にはまだまだ問題がたくさんあり、不幸な人もたくさんいるのでその人たちの意見も届いたり、解決策を出せる場所が必要。

解決策

政治系のSNSを作っちゃお!!!

やること

オープンソースのSpectrumを公開サーバーに移す

https://github.com/withspectrum/spectrum/blob/alpha/docs/deployments.md

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む