TokyoFacebookTwitterHatenaPocket米国版2ちゃんねるとも言われる巨大掲示板Reddit。バックエンドにFirebase、フロントエンドにReactを使うことで、時間をかけずにReddit風掲示板を作る方法を解説します。Reactはユーザーインターフェイスの構築に使われるJavaScriptのライブラリーです。Create-React-Appを利用すれば、Reactアプリケーションのひな形を簡単に準備できます。この記事ではCreate-React-AppとFirebaseを使って、ユーザーが作成したリンクにほかのユーザーが投票できる機能を持つRedditのようなアプリを構築します。完成形のデモを実際に操作してみてください。Firebaseを使う理由Firebaseは、ユーザーの投票を即座に反映するような、リアルタイムのデータを簡単にユーザーへ提示できます。実装には、Firebaseのリアルタイムデータベースを使います。ReactアプリケーションをFirebaseを使ってすばやく立ち上げる方法を解説します。Reactを使う理由Reactは、主にコンポーネントアーキテクチャーを使ってユーザーインターフェイスを構築するために使います。それぞれのコンポーネントは内部ステート(State)を持つか、プロップ(Prop)としてデータを受け取ります。Reactを使うには、2つのコンセプト「ステートとプロップ」を理解しましょう。ステートとプロップでアプリケーションの状態が規定されます。ステートとプロップに関してはReactドキュメントに目を通してください。メモ:ReduxやMobXのようなステートコンテナも存在しますが、シンプルさを優先して、この記事では扱いません。この記事のプロジェクトはすべてGithubで入手できます。プロジェクトを設定プロジェクトを立ち上げて依存オブジェクトを設定する方法を、ステップごとに説明します。Create-React-Appをインストール次のコマンドをターミナルに打ち込んで、Create-React-Appをインストールします。create-react-appグローバルインストールすれば、どのフォルダーからでもReactプロジェクトのひな形を作成できます。reddit-cloneという名前の新しいアプリを作成します。reddit-clone新しいCreate-React-Appプロジェクトのひな形がreddit-cloneディレクトリに作成されます。Bootstrapを終えると、reddit-cloneディレクトリへ移動し開発用サーバーを起動します。starthttp://localhost:3000/にアクセスして、アプリのスケルトンが起動していることを確認してください。アプリの大枠メンテナンスしやすくするために、コンテナとコンポーネントを分離しています。コンテナは判断を伴うコンポーネントで、アプリケーションのビジネスロジックを記載して、Ajaxリクエストを処理します。コンポーネントは判断を伴わないデザインのコンポーネントです。内部のステートを持ち、コンポーネントのロジックをコントロールします(例:コントロールされたインプットコンポーネントの現在のステートを表示)。不要なロゴとCSSファイルを消去して、次のフォルダー構成にします。componentsフォルダーとcontainersフォルダーを作成してApp.jsをcontainers/Appフォルダーに移動し、utilsフォルダーにregisterServiceWorker.jsを作成します。src/containers/App/index.jsには次の内容を記載します。App;src/index.jsは次のとおりです。World」と表示されます。ここまでのファイルをGithubにコミットしました。React-Routerを追加React-Routerはアプリのルートを定義するツールで、カスタマイズの自由度が高く、Reactとセットで広く使われています。ここではバージョン3.0.0を使います。react-router@3.0.0srcフォルダーに新しいファイル「routes.js」を作成し、次のコードを記載します。Routes;Routerコンポーネントの内にすべてのRouteコンポーネントを配置します。Routeコンポーネントのpathプロップに従って、componentプロップに渡されたコンポーネントがページ上にレンダリングされます。ここではRouterコンポーネントを使ってルートURL(/)にAppコンポーネントをロードします。</Route></Router>上記のコードでも動作します。World!</div>がマウントされます。次にsrc/index.jsからroutes.jsを呼び出します。src/index.jsには次のコードを記載します。document.getElementById('root'));registerServiceWorker();routes.jsからRouterコンポーネントをマウントします。historyプロップを渡すことで、Routesが履歴を追跡できます。ここまでのファイルをGithubにコミットしました。Firebaseを追加Firebaseのアカウントを持っていなければ、Webサイトにアクセスして取得してください(無料です)。アカウント作成後ログインし、コンソールの「プロジェクトを追加」をクリックします。プロジェクト名(ここではreddit-clone)を入力、国を選択して、「プロジェクトを作成」ボタンをクリックします。デフォルトだと、Firebaseのデータ読み込みと書き込みにはユーザー認証が必要です。そこで次に進む前にデータベースのルールを変更します。プロジェクトを選択して左端のDatabaseタブをクリックして、データベースを表示し、上部のRulesタブをクリックして、次のデータを含む画面を表示します。}}以下の通り修正します。}}これでログインしていないユーザーでもデータベースを更新できるようになりました。データベースの更新に認証が必要なフローにするのなら、Firebaseのデフォルトルールのまま使います。この記事ではアプリケーションをシンプルにするために、ユーザー認証は用いません。重要:この修正をしないと、アプリからFirebaseのデータベースを更新できません。次のコマンドで、firebaseのnpmモジュールをアプリに追加します。firebase以下のコードでFirebaseをApp/index.jsにインポートします。app」のボタンが表示されます。そのボタンをクリックすると、config変数の値が表示されます。これはcomponentWillMountメソッドで使います。Firebaseの設定ファイルをfirebase-config.jsという名前で作成します。Firebaseへの接続に必要なすべての設定情報を、このファイルに記載します。"490290211297"};Firebaseの設定情報をApp/index.jsにインポートします。'./firebase-config';constructorでFirebaseへのデータベース接続を初期化します。firebase.initializeApp(config);}componentWillMount()ライフサイクルフックで、先ほどインストールしたfirebaseパッケージのinitializeAppメソッドを呼び出して、config変数を渡します。このオブジェクトにはアプリに関するデータすべてを格納します。initializeAppメソッドはアプリをFirebaseデータベースに接続して、データの読み書きができるようにします。設定できたか確かめるため、Firebaseにデータを追加します。Databaseタブへ移動し、次のデータをデータベースに追加してください。Addをクリックすると、データベースに保存されます。データを画面に表示するコードをcomponentWillMountメソッドに追加します。}firebase.database()でデータベースサービスへの参照を取得します。ref()でデータベースからの具体的な参照を取得します。ref('posts')でデータベースからposts参照を取得して、postsRefに格納します。...)はデータベースが変更されたときに変更後の値を扱います。データベースイベントに基づいてリアルタイムでユーザーインターフェイスを更新するときに使用します。...)がデータを返すのは1度だけで、再読み込みが不要なデータに適しており、頻繁に更新されたりアクティブリスニングが必要なデータには不向きです。更新後の値をon()コールバックで取得して、postsステートに保存します。これでコンソールにデータが表示されます。子要素にもデータを渡せるように、App/index.jsのrender関数を書き換えます。);}react-routerで渡されたpostsデータのすべてを子要素で使えるようにします。this.props.childrenの存在を確認し、存在すれば要素をクローンして、すべてのプロップを子要素に渡しています。動的な子要素にプロップを渡す効率的な方法です。cloneElementは、this.props.childrenに存在するプロップと渡すプロップ(firebaseRef、posts、loading)をシャローマージします。これでfirebaseRefとposts、loadingプロップをすべてのRoutesで使えるようになります。ここまでファイルをGithubにコミットしました。アプリをFirebaseに接続Firebaseはデータをオブジェクトとして保存します。標準では配列をサポートしていないので、データを以下の形式で保存します。上記のスクリーンショットのデータを手動で追加して、ビューをテストできるようにします。Postsのビューを追加すべてのPostsを表示するビューを追加します。次の内容でsrc/containers/Posts/index.jsを作成します。Posts;データをマップして、ユーザーインターフェイスにレンダリングし、routes.jsに追加します。</Route></Router>...Postsが/postsルートに表示されます。Postsコンポーネントをcomponentプロップに渡し、/postsをReact-RouterのRouteコンポーネントのpathプロップに渡します。localhost:3000/postsにアクセスすると、FirebaseのデータベースからPostsが表示されます。ここまでのファイルをGithubにコミットしました。新しいPostを追加するビューを作成します。次の内容でsrc/containers/AddPost/index.jsを作成します。AddPost;handleChangeメソッドが、インプットボックスに入力された値でステートを更新します。ボタンをクリックするとhandleSubmitメソッドが呼び出されて、データベースに書き込むAPIのリクエストを出します。この際、子要素へ渡したfirebaseRefプロップを使います。this.state.title});上記のコードで、現在のタイトルの値をデータベースに書き込みます。新しいPostがデータベースに保存されると、インプットボックスを空にして、再び新しいPostが追加できるようにします。Routesに追加します。Routes;/add-postルートを追加して、新しいPostをこのルートから追加できるようにしました。AddPostコンポーネントをコンポーネントプロップに渡しています。Firebaseは配列をサポートしていないためsrc/containers/Posts/index.jsのrenderメソッドを修正して、配列の代わりにオブジェクトを走査できるようにします。}localhost:3000/add-postにアクセスすると、新しいPostを追加できるようになっています。submitボタンをクリックすると、即座に新しいPostがPostページに表示されます。ここまでのファイルをGithubにコミットしました。投票機能を追加ユーザーがPostに投票する機能を追加します。src/containers/App/index.jsのrenderメソッドを修正します。firebase.database()に修正し、Firebaseのsetメソッドで投票数を更新します。Firebaseのrefが増えても、firebaseプロップで簡単に対応できます。投票機能を実装する前に、src/containers/AddPost/index.jsのhandleSubmitメソッドを少し修正します。...}firebaseRefプロップをfirebaseプロップに名称変更したので、this.props.firebaseRef.pushをthis.props.firebase.ref('posts').pushに変更します。src/containers/Posts/index.jsを修正して、投票機能を実装します。renderメソッドを修正します。);}ボタンをクリックすると、Firebaseデータベースの賛成票か反対票の数が増えます。このロジックをhandleUpvote()メソッドとhandleDownvote()メソッドに記述します。});}2つのメソッドは、ユーザーが投票ボタンをクリックしたときに、データベースの賛成票数か反対票数に1を加えて、即座にブラウザーへ反映します。localhost:3000/postsを2つのタブで開いて投票ボタンをクリックすると、両方のタブがほぼ即時に更新されます。これがFirebaseをはじめ、リアルタイムデータベースの真骨頂です。ここまでのファイルをGithubにコミットしました。RouteをアプリケーションのIndexRouteに追加します。ここまでのファイルもGithubにコミットしています。最後に最終形でもデザインをしていないので、殺風景なままです(デモはスタイルを追加しました)。プログラムが複雑になって記事が長くなるのを避けるために認証プロセスを実装しませんでしたが、実際のアプリケーションには必要でしょう。Firebaseは、バックエンドアプリケーションの開発とメンテナンスが不要なので、API開発に多大な時間を費やすことなくリアルタイムデータを扱えます。FirebaseはReactと相性が良いことも記事から分かるでしょう。Wanyoikeが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者のみなさんに感謝します。Ghoshインタラクティブデザインに強いフリーランスのWebデザイナー。Infismashの創立者で、WordPressのテーマ開発に力を入れています。オープンソースソフトウェアの大ファンです。