- 投稿日:2019-05-12T16:11:37+09:00
React+Redux+TypescriptでFirebaseのLogin機能を実装する
最近Reactをよく触ってて、その際にReactからFirebase Loginを実装する方法について学んだのでその知見を書きます。
Firebase Login機能のサンプルコードはこちらに置いてあります。実装ではなるべくモダンな開発環境で使われてそうなライブラリを使いたかったのでReact、Redux、Typescriptを使っています。
ESLintやPretter、lint-stagedの設定もなるべく追加するようにしています。
また、Reactコンポーネントはクラスを使って実装するのではなく、ここではなるべく関数コンポーネントを使って書くようにしてます。アプリの概要
Google Loginボタンを押すとGoogleのログイン認証ページにリダイレクトして認証をします。
ユーザ認証が成功するとguestの部分がユーザ名に、ボタンの名前はGoogle Logoutに変わります。Presentational ComponentとContainer Component
見た目の部分はcomponents/Auth.tsxで実装しています。
描画する際に必要なプロパティはAuthPropsで定義しています。components/Auth.tsximport 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.tsxconst 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.tsximport { 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.tsconst reducers: Reducer<ApplicationState> = combineReducers<ApplicationState>({ auth, }); export default reducers;combineReducersは指定したreducerを統合したreducerの状態ツリーを作成します。
作成されたreducerはindex.tsx内のcreateStoreの引数として渡します。index.tsximport 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.jsexport 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 ログインを使用した認証
- 投稿日:2019-05-12T15:28:53+09:00
Firebaseを使ってReactの認証処理をあっという間に完成させる
手順
- プロジェクトを作成する
- アプリを追加する
- firebase.jsの作成
- ログイン処理の実装
プロジェクトを作成する
プロジェクトの作成は、Firebaseのトップページから簡単な設定で完了することができます。
アプリを追加する
プロジェクトのトップからアプリを追加するとFirebase SDKの必要な情報を取得することができます。
firebase.jsの作成
Firebase SDKの情報が取得できたら、Firebase Authentificationを利用するためにfirebase.jsを作成します。
コードは下記の通り。
firebase.jsimport 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.jsfirebase.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
- 投稿日:2019-05-12T14:01:24+09:00
OSSで政治系のことについて議論できるChatスペースを作りたい
課題
日本ではSNSで政治のことは呟かれない
日本人は周りの人に合わせる癖があるので、SNSの投稿は基本的にキラキラしたものが多いです。自分がキラキラした生活を送っていることを投稿すればするほど、みんなからのいいねがたくさん来たり、みんなと同じような投稿をしたりすると共感が得られるシステム、それがSNSです。だからいつもSNSでフォロワーの多い人や友達のツイートを見て、同じような投稿をし、共感をえて、いいねをもらう。一つのゲームみたいなもので、ポケモンGOとかとあまり変わりありません。
キラキラしたものをinstagramに載せるのが悪いと言ってる訳ではなく、社会にはまだまだ問題がたくさんあり、不幸な人もたくさんいるのでその人たちの意見も届いたり、解決策を出せる場所が必要。解決策
政治系のSNSを作っちゃお!!!
やること
オープンソースのSpectrumを公開サーバーに移す
https://github.com/withspectrum/spectrum/blob/alpha/docs/deployments.md
