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

★前回の記事

yucatio.hatenablog.com

データの読み込み部分を、ローカルからFirebase Realtime Database(以下、Firebase)に変更します。

読み込み部分の作成

データ読み込みのコードはcontainerに記載します。タスク一覧(todos)をFirebaseから取得します。

src/containers/VisibleTodoList.js

// importを追加
import { compose } from 'redux'
import { firebaseConnect } from 'react-redux-firebase'

// 中略

const firebaseQueries = ['todos'];  // #3

const VisibleTodoList = compose(   // #1
  firebaseConnect(firebaseQueries),  // #2
  connect(
    mapStateToProps,
    mapDispatchToProps
))(TodoList)
  • composeでFirebaseとReduxを合成します(#1)。
  • Firebaseからデータを取得するには、firebaseConnectの引数に、取得内容の配列を渡します(#2, #3)。配列の各要素には、Firebaseへの問い合わせ内容を記載します。
const firebaseQueries = ['todos'];

は、以下と同様です。

const firebaseQueries = [
    { type: 'value', path: '/todos' }
];

このように書くことで、/todoというパスのデータを読み取ります。データの変更は、valueイベントでトリガされるようになります。 value以外の設定(onceやchild_added)の設定の仕方や取得件数の設定方法は公式ドキュメント (Queries · React Redux Firebase)を参照してください。

取得したデータは、state.firebase.data.todosに保存されているので、mapStateToPropsを変更します。

src/containers/VisibleTodoList.js

 const mapStateToProps = state => {
   return {
    todos: getVisibleTodos(state.firebase.data.todos, state.visibilityFilter)  // 変更
   }
 }

読み込み部分が完成しました。react-redux-firebaseを使用して簡単に実装することができました。

表示部分の修正

次に、表示部分を変更します。Firebaseのデータが読み込まれるまでに時間がかかるので、isLoadedを利用して読み込みが終わるまで代替のテキストを表示します。 また、リストが空だった場合のために、isEmptyを利用して、空の旨を表示します。 読み込みが完了したら、タスクのリストを表示します。

変更前のtodosのデータは、{id, text, completed}というオブジェクトの配列でしたが、Firebaseから取得したデータは、${key}: {text, completed}というプロパティの集まりです。この場合の対処法として、

  1. TodoListでFirebase形式のオブジェクトを扱うように変更する
  2. VisibleTodoListでtodosを配列に変更して、TodoListに渡す

の2つが考えられますが、今回は1番目の方法にしました。

TodoListを書き換えます。

src/components/TodoList.js

import React from 'react'
import { isLoaded, isEmpty } from 'react-redux-firebase'  // #1
import PropTypes from 'prop-types'
import Todo from './Todo'

const TodoList = ({todos, onTodoClick}) => {
  if (!isLoaded(todos)) {  // #2
    return <div>タスク一覧を読み込み中…</div>
  }
  if (isEmpty(todos)) {  // #3
    return <div>タスクがありません。</div>
  }

  return (
    <ul>
      {Object.keys(todos).map((key) => (  //#4
        <Todo key={key} {...todos[key]} onClick={() => onTodoClick(key)}/>
      ))}
    </ul>
  )
}

// 後略
  • isLoadedisEmptyreact-redux-firebaseからimportします(#1)。
  • todosがまだ読み込まれていない時に、読み込み中の文言を表示します(#2)。
  • todosが空の時に、タスクが空の文言を表示します(#3)。
  • 各タスクを表示するために、Object.keys(todos)で一旦keyの配列を作成し、それに対してmapを呼びます(#4)。

PropTypesも変更します。

src/components/TodoList.js

TodoList.propTypes = {
  todos: PropTypes.objectOf(
    PropTypes.shape({
      completed: PropTypes.bool.isRequired,
      text: PropTypes.string.isRequired
    })
  ),
  onTodoClick: PropTypes.func.isRequired
}

動作確認

ブラウザで確認しましょう。 Firebaseに登録したデータが表示されていれば成功です!他の機能は動かなくなってしまったので、次回以降で修正します。

f:id:yucatio:20180926125229p:plain

うまく動かない場合は、Firebaseの設定(src/firebase/config.js)は自身のものになっているか、コピペミス、意図しない空白が入っていないか確認してください。 databaseURLが間違っている場合は、 ブラウザのコンソールに @firebase/database: FIREBASE WARNING: Firebase error. Please ensure that you spelled the name of your Firebase correctly (https://todo-sample-xxxxx.firebaseio.com) と表示されます。

コンソールにRRF: Error retrieving data for path: todos, storeAs: undefined. Firebase: Error: permission_denied at /todos: Client doesn't have permission to access the desired data.のエラーが表示される場合は、 Realtime Databaseのパーミッション設定が下記のようになっているかどうか確認してください。

f:id:yucatio:20180926143327p:plain

★次回の記事

yucatio.hatenablog.com

★目次

yucatio.hatenablog.com