yucatio@システムエンジニア

趣味で作ったものいろいろ

タスクの読み込みパスの変更 (STEP 2 : ユーザ認証を行なって、自分だけが読み込めて書き込めるタスク管理アプリを作成する - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

データのパスの変更

ユーザごとにデータを保存するように変更します。 今までのパスは、/todoの下に各タスクを保存していましたが、STEP 2 では /todos/${uid}のように、各ユーザIDの下にタスクを保存するように変更します。

VisibleTodoListの変更

uidstate,firebase.auth.uidに保存されています。firebaseConnect関数はstateを渡さないので、 uidの値は親コンポーネントから受け渡します。

src/containers/VisibleTodoList.js

const firebaseQueries = ({uid}) => (  // #1
  [`todos/${uid}`]
)

const mapStateToProps = ({visibilityFilter, firebase: {data : {todos}}}, {uid}) => {
  return {
    todos: getVisibleTodos(todos && todos[uid], visibilityFilter)  // #2
  }
}
  • firebaseQueriesを配列から関数に変更します(#1)。関数はpropsを第1引数に取り、配列を返します。親コンポーネントからuidの値を受け取り、/todos/${uid}パスのデータを読み取ります。
  • todosのパスを変更します。firebaseのtodosがnullの場合があるので、todos &&の条件を追加します。(#2)

TodoComponentの変更

TodoComponentの変更します。uidの受け渡しをするのと、ログインしていない時に下位コンポーネントを表示しないように変更をします。

src/components/TodoComponent

// 前略
import { connect } from 'react-redux'
import { isEmpty, isLoaded } from 'react-redux-firebase'
import PropTypes from 'prop-types'

let TodoComponent = ({uid, authenticating, authenticated}) => {
  if (authenticating) {  // #4
    return <div>ログイン中...</div>
  }
  if (!authenticated) {  //#5
    return <div>タスク一覧を表示するには、ログインしてください。</div>
  }
  return (
    <div>
      <AddTodo />
      <NoticeForTodo />
      <VisibleTodoList uid={uid} />  {/* #6 */}
      <Footer />
    </div>
  )
}

TodoComponent.propTypes = {
  uid: PropTypes.string,
  authenticating: PropTypes.bool.isRequired,
  authenticated: PropTypes.bool.isRequired
}

const mapStateToProps = ({firebase: {auth, auth: {uid}}}) => ({
  uid,  // #1
  authenticating:  !isLoaded(auth),  // #”2
  authenticated: !isEmpty(auth)  // #3
})

TodoComponent = connect(
  mapStateToProps
)(TodoComponent)

export default TodoComponent;
  • stateからを取得します(#1)。
  • 認証情報が読み込み中か(#2)と、認証情報が存在するか(#3)をstateから取得します。
  • 認証情報読み込み中にその旨を表示します(#4)。
  • ログインしていない時に、タスクはログイン後見られる旨を表示します(#5)。
  • uidをVisibleTodoListに渡します(#6)。

動作確認

未ログイン時。タスク追加ダイアログやフィルターも表示されません。

f:id:yucatio:20181003115328p:plain

ログイン時。ユーザごとのタスクはまだありません。

f:id:yucatio:20181003115453p:plain

以上で読み込みパスの変更ができました。

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

Firebaseを利用した認証機能の作成(2) view (STEP 2 : ユーザ認証を行なって、自分だけが読み込めて書き込めるタスク管理アプリを作成する - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

Viewの実装

ログイン機能のviewを作成します。未ログイン時にはGoogleアカウントでログインボタンを表示し、ログイン時には名前とログアウトボタンを表示します。

src/components/Login.js

import React from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { isLoaded, isEmpty } from 'react-redux-firebase'
import { loginWithGoogle, logout } from '../actions/authActions'

let Login = ({ auth, loginWithGoogle, logout }) => {
  if (!isLoaded(auth)) {  // #4
    return (<div>ログイン中...</div>);
  }
  if (isEmpty(auth)) {  // #5
    return (
      <button onClick={loginWithGoogle}>Googleアカウントでログイン</button>
    )
  }
  return (
    <div>
      {auth.displayName} さん   {/* #6 */}
      <button onClick={logout}>ログアウト</button>   {/* #7 */}
    </div>
  );
}

Login.propTypes = {
  auth: PropTypes.object.isRequired,
  loginWithGoogle: PropTypes.func.isRequired,
  logout: PropTypes.func.isRequired
}

const mapStateToProps = state => (
  { auth: state.firebase.auth }  // #1
)

const mapDispatchToProps = dispatch => {
  return {
    loginWithGoogle: () => dispatch(loginWithGoogle()),  // #2
    logout: () => {dispatch(logout())  // #3
    }
  }
}

Login = connect(
  mapStateToProps,
  mapDispatchToProps
)(Login)

export default Login;
  • 認証情報は、state.firebase.authで取得できます(#1)。authというプロパティ名でviewに渡します。
  • ログイン関連のfunctionをviewに渡します(#2, #3)。
  • 認証情報の読み込み中は、isLoaded(auth)falseになるので、その間は読み込み中である旨を表示します(#4)。
  • ログアウトしている場合は、isEmpty(auth)trueになるので、ログインボタンを表示します(#5)。
  • ログインしている場合は、ユーザ名(#6)とログアウトボタン(#7)を表示します。

動作確認

ログイン、ログアウトの機能ができたので、動作確認します。

ログアウト状態です。

f:id:yucatio:20181002144905p:plain

Googleでログインボタンを押すと、画面が切り替わり、アカウント選択画面になります。

f:id:yucatio:20181002152558p:plain

アカウントを選択すると、元の画面に戻り、少しの間ログイン中...と表示されます。

f:id:yucatio:20181002152752p:plain

読み込みが終わると、ログイン名とログアウトボタンが表示されます。

f:id:yucatio:20181002153033p:plain

ログアウトを押すと、ログインボタンが表示されます。

f:id:yucatio:20181002144905p:plain

Firebaseのデータも確認しておきましょう、

Firebase Console > Authentication > ユーザに、ログインしたことのあるユーザ一覧が表示されます。

f:id:yucatio:20181002154739p:plain

Databaseのデータタブで、/userパスにユーザの情報が格納されていることが確認できます。

f:id:yucatio:20181002161204p:plain

以上で認証機能の作成は完了です。

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

Firebaseを利用した認証機能の作成(1) actionとreducer (STEP 2 : ユーザ認証を行なって、自分だけが読み込めて書き込めるタスク管理アプリを作成する - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

認証機能を実装します。react-redux-firebaseのAPIを利用します。

ユーザ情報の保存先の設定

始めにindex.jscreateStoreWithFirebaseを変更します。

src/index.js

const createStoreWithFirebase = compose(
  applyMiddleware(thunk.withExtraArgument({getFirebase})),
  reactReduxFirebase(firebase, {userProfile: 'users'})  // 変更
)(createStore);

reactReduxFirebaseの引数に{userProfile: 'users’}を追加します。このようにすると、Firebase Realtime Databaseの/userパスにユーザのデータが保存されます。(/userのデータはSTEP 3で使用します。)

ログイン・ログアウトactionの作成

ログインとログアウトのactionを作成します。公式のAuthのページ を参考に進めていきます。

src/actions/index.js

下記を追加します。

// auth actions
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'
export const LOGIN_ERROR = 'LOGIN_ERROR'
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'
export const LOGOUT_ERROR = 'LOGOUT_ERROR'

認証actionを実装します。

src/actions/authActions.js(新規ファイル)

import { LOGIN_SUCCESS, LOGIN_ERROR, LOGOUT_SUCCESS, LOGOUT_ERROR } 
  from './'

const loginSuccess = () => ({
  type: LOGIN_SUCCESS
})

const loginError = (err) => ({
  type: LOGIN_ERROR,
  err
}) 

const logoutSuccess = () => ({
  type: LOGOUT_SUCCESS
})

const logoutError = (err) => ({
  type: LOGOUT_ERROR,
  err
})

export const loginWithGoogle = () => {
  return (dispatch, getState, {getFirebase}) => {
    const firebase = getFirebase();
    firebase.login({provider: 'google'}) // #1
    .then(() => {
      dispatch(loginSuccess());
    }).catch(err => {
      dispatch(loginError(err));
    });
  }
}

export const logout = () => {
  return (dispatch, getState, {getFirebase}) => {
    const firebase = getFirebase();
    firebase.logout()  // #2
    .then(() => {
      dispatch(logoutSuccess());
    }).catch(err => {
      dispatch(logoutError(err));
    });
  }
}
  • ログインを行います(#1)。providerにgoogleを指定します。
  • ログアウトを行います(#2)。

actionの中心となるのは、上記の2行のコードだけです。非常に短いコードでログイン、ログアウトが実装できました。

reducerの実装

reducerの実装をします。ログアウト時に設定をクリアします。

src/reducers/todos.js

import { LOGOUT_SUCCESS, ADD_TODO_REQUEST, ADD_TODO_SUCCESS, ADD_TODO_ERROR,
  TOGGLE_TODO_REQUEST, TOGGLE_TODO_SUCCESS, TOGGLE_TODO_ERROR }
   from '../actions/'

const todos = (state = {}, action) => {
  switch (action.type) {
    // 中略
    case LOGOUT_SUCCESS :  // 追加
      return {}
    default:
      return state
  }
}

src/reducers/visibilityFilter.js

import { LOGOUT_SUCCESS, SET_VISIBILITY_FILTER } from '../actions/' // 変更
// 中略

const visibilityFilter = (state = VisibilityFilters.SHOW_ALL, action) => {
  switch (action.type) {
    // 中略
    case LOGOUT_SUCCESS:   // 追加
      return VisibilityFilters.SHOW_ALL
    default:
      return state
  }
}

以上でログインのactionとreducerの実装が完了しました。

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

事前準備 : コンポーネント階層の変更 (STEP 2 : ユーザ認証を行なって、自分だけが読み込めて書き込めるタスク管理アプリを作成する - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

認証機能作成の前に、認証用のコンポーネントの作成とタスク関連のコンポーネントに分けます。

現在のコンポーネントツリー

f:id:yucatio:20181001095447p:plain

新しいコンポーネントツリー(緑色が新規コンポーネント)

f:id:yucatio:20181001095458p:plain

コードを変更します。

src/components/App.js

import React from 'react'
import Login from './Login'
import TodoComponent from './TodoComponent'

const App = () => (
  <div>
    <Login />
    <TodoComponent />
  </div>
)

export default App;

src/components/TodoComponent.jsを新規作成します。

import React from 'react'
import Footer from './Footer'
import NoticeForTodo from './NoticeForTodo'
import AddTodo from '../containers/AddTodo'
import VisibleTodoList from '../containers/VisibleTodoList'

const TodoComponent = () => (
  <div>
    <AddTodo />
    <NoticeForTodo />
    <VisibleTodoList />
    <Footer />
  </div>
)

export default TodoComponent;

空の文字列を返すLoginコンポーネントを用意します。

src/components/Login.js

import React from 'react'

const Login = () => (
  ''
)

export default Login;

コンポーネント階層の変更が完了しました。

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

Firebaseのログイン機能の有効化 (STEP 2 : ユーザ認証を行なって、自分だけが読み込めて書き込めるタスク管理アプリを作成する - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

Firebaseを使用したログイン機能

FirebaseではGoogleFacebooktwitterなどと連携したログイン機能を提供しています。各機能を有効化するために、コンソールで操作します。

ログイン機能の有効化

1. Firebase Consoleを表示します。

2. 対象のプロジェクトを開きます。

3. Authentication > ログイン方法を開きます。

f:id:yucatio:20180930145648p:plain

4. 今回はGoogleのログイン機能を使用するので、Googleを選択します。

5. 有効にするをONにして、サポートメールを選択し、保存を押します。

f:id:yucatio:20180930150030p:plain

6. Googleのログイン機能が有効になりました。

f:id:yucatio:20180930150221p:plain

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

STEP 2での成果物 (STEP 2 : ユーザ認証を行なって、自分だけが読み込めて書き込めるタスク管理アプリを作成する - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

STEP 2では、ユーザごとのタスクを管理できるアプリを作成します。 ログインボタンを設置し、ログイン後にタスクの閲覧、更新を可能にします。

ログイン時↓

f:id:yucatio:20181005121256p:plain

未ログイン時↓

f:id:yucatio:20181003115328p:plain

簡単のため、今回はGoogleアカウントでの認証のみ実装します。

DBツリーは以下のようになります。

/
  |_ ユーザ1
  | |_ タスク1
  | | |_ text : '起きる'
  | | |_ completed : true
  | |_ タスク2
  |   |_ text : '朝ごはん'
  |   |_ completed : false
  |_ ユーザ2
  | |_ タスク3
  | | |_ text : '腕立て伏せ'
  | | |_ completed : false
  | |_ タスク4
  |   |_ text : 'ジョギング'
  |   |_ completed : true
    ...

それでは、STEP 2のチュートリアルを始めましょう。

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com

Firebaseアプリの公開 (STEP 1 : 誰でも読み込み・書き込みできるタスク管理アプリを作る - React + Redux + Firebase チュートリアル)

★前回の記事

yucatio.hatenablog.com

アプリが完成したので、Firebaseにアプリを公開します。

ビルドします。

$ yarn run build

一旦ローカルで正常に動くか確認しましょう。

$ firebase serve

http://localhost:5000にアクセスして、動作確認しましょう。

確認が終わったら、Firebaseにデプロイします。

$ firebase deploy

=== Deploying to 'todo-sample-xxxxx’…

i  deploying database, hosting
i  database: checking rules syntax...
✔  database: rules syntax for database todo-sample-xxxxx is valid
i  hosting[todo-sample-xxxxx]: beginning deploy...
i  hosting[todo-sample-xxxxx]: found 7 files in build
✔  hosting[todo-sample-xxxxx]: file upload complete
i  database: releasing rules...
✔  database: rules for database todo-sample-xxxxx released successfully
i  hosting[todo-sample-xxxxx]: finalizing version...
✔  hosting[todo-sample-xxxxx]: version finalized
i  hosting[todo-sample-xxxxx]: releasing new version...
✔  hosting[todo-sample-xxxxx]: release complete

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/todo-sample-xxxxx/overview
Hosting URL: https://todo-sample-xxxxx.firebaseapp.com

無事デプロイできたので、https://todo-sample-xxxxx.firebaseapp.com にアクセスします。(todo-sample-xxxxは自分のプロジェクトIDに置き換えてください。)

f:id:yucatio:20180930141732p:plain

アプリが公開できました!

これでSTEP 1は終了です。おめでとうございます!STEP 2ではユーザ認証を追加します。

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com