React & Redux & Router & Firebase でGoogleソーシャルログインの実装

# React & Redux & Router & Firebase でGoogleソーシャルログインの実装

私のTwitterアカウントは https://twitter.com/solt9029 です。
今回は、初めてFirebaseのAuthenticationを利用したので、その記録として記事を書きます。

記事自体では多く説明を端折りますが、サンプルを割と丁寧に簡潔に作成した（つもり）ので、詳しくはそちらを見てください。
サンプル： https://github.com/solt9029/ReactReduxFirebaseLoginTutorial

## サンプルコードがどう動くか

### ルーティング

- / : Topコンポーネントを表示する（ボタンを押すとログインできる）
- /home : UserOnlyコンポーネントを表示する（ログインしている状態でしか見られない）

### Topコンポーネント

```js:/src/components/Top.js
import React from 'react';

export default class Top extends React.Component {
  render() {
    return (
      <div>
        <h2>Top</h2>
        <button onClick={() => this.props.login()}>login</button>
      </div>
    )
  }
}
```

### UserOnlyコンポーネント

```js:/src/components/UserOnly.js
import React from 'react';
import { Redirect } from 'react-router-dom';

export default class UserOnly extends React.Component {
  render() {
    return (
      <div>
        <h2>UserOnly</h2>
        { this.props.displayName }
      </div>
    )
  }
}
```

## 簡単な解説です（気が向いたら追記しまくります！）

### Firebaseの設定

こんな感じで書きます。configに各自のapiKeyなどを格納します。

```js:/src/firebase/index.js
import firebase from 'firebase';

import { config } from './config';

firebase.initializeApp(config);

export const provider = new firebase.auth.GoogleAuthProvider();
export const auth = firebase.auth();
export const database = firebase.database();
export default firebase;
```

### ユーザのデータ

以下のような項目をユーザのデータとして保持することにします。

```js:/src/reducers/user.js
const initialState = {
  displayName: null,
  email: null,
  phoneNumber: null,
  photoURL: null,
  providerid: null,
  uid: null
};

export default (state = initialState, action) => {
  switch (action.type) {
    case 'START_LOGIN':
      return initialState;
    
    case 'END_LOGIN':
      return {
        ...state,
        displayName: action.payload.displayName,
        email: action.payload.email,
        phoneNumber: action.payload.phoneNumber,
        photoURL: action.payload.photoURL,
        providerId: action.payload.providerId,
        uid: action.payload.uid
      }

    default:
      return state;
  }
}
```

### ログインしている状態でのみ閲覧できるルーティングコンポーネント

uidがあるかどうかでとりあえず確認しています。

```js:/src/components/PrivateRouter.js
import React from 'react';  
import { Redirect, Route } from 'react-router-dom';

const PrivateRoute = ({ component: Component, uid, ...rest }) => {
  return (
    <Route {...rest} render={props => (
      uid ? <Component {...props} /> : <Redirect to="/" />
    )} />
  );
};

export default PrivateRoute;
```

### おおもとのAppコンポーネント

```js:/src/App.js
import React, { Component } from 'react';
import { Switch, Route, Redirect, Link } from 'react-router-dom';
import UserOnly from './containers/UserOnly';
import Top from './containers/Top';
import PrivateRoute from './containers/PrivateRoute';

export default class App extends Component {
  render() {
    return (
      <div className="App">
        <ul>
          <li><Link to="/">トップページ</Link></li>
          <li><Link to="/home">ユーザ専用ページ</Link></li>
        </ul>
        <Switch>
          <Route exact path="/" component={Top} />
          <PrivateRoute exact path="/home" component={UserOnly} />
        </Switch>
      </div>
    );
  }
}
```

端折りまくりですが以上です！