Phoenix + Reactでチャットアプリを作ろう(Part 2)

React Hooksを使ったGroupの作成・参照画面作成

Ichizo Umehara
11 min readMar 10, 2020

アプリ概要はPhoenix + Reactでチャットアプリを作ろう(Intro)参照。

ここまでのコードはP1_3_ADD_CORSブランチ参照。

Part 1で紹介したGroup一覧取得、Group作成、Group詳細のJSON REST APIが構築されていることを前提とする。

本章(Part 2)ではReact Hooksを使って3つの画面を作成する。

グループ一覧画面(Group List)

  • グループ名一覧:グループ名をクリックするとグループ詳細画面に遷移
  • 新規作成ボタン:ボタンをクリックすると新規グループ作成画面に遷移

グループ詳細画面(Group Detail)

  • メッセージ一覧:表示のみ
  • 新規メッセージフォーム:ユーザー名とメッセージ分を入力して、Sendボタンで送信できる

グループ新規作成画面(New Group)

・グループ名を入力して、Createボタンで送信できる

作業項目は以下の通り。

  • プロジェクトファイル作成と初期設定:カスタムな内容ではないけど、サーバを起動すればブラウザからアクセスできる状態
  • Home 画面作成
  • スタイルガイド作成:コンポーネント間で使い回せるスタイルを定義する。
  • Group詳細画面作成
  • Group作成画面作成

プロジェクトファイル作成と初期設定

create-react-appを使うとReactアプリの枠組みを作ってくれる。

プロジェクトのルートで作成しよう。ディレクトリ名はapiと揃うようにwebなどが妥当だろう。ただ、アプリ名ではないので、chatterでアプリを自動生成してから、ディレクトリ名だけwebにリネームする。

cd chatter
npx create-react-app chatter
mv chatter web

新しくできたアプリをnpm run startで立ち上げると画面が見えるはず

cd web
npm run start
http://localhost:3000

最初のテストを書こう。

とりあえず、ヘッダーの文字が表示されることを確認しよう。

/src/App.test.js

テストを通すための最小限の変更をすると、

/src/App.js

パスするはず。

npm test

次に、画面遷移にはルーターが必要なのでreact-routerをインストールしよう。

npm install --save react-router-dom

BrowserRouterとSwitchを使えば、各画面にパスを紐付けられる。

アプリを renderしたらデフォルトでHome画面の”My Chat Groups”の文字列が表示されるようテストを更新して、

/src/App.test.js

BrowserRouterを使った実装をしよう。

/src/App.js

テストを走らせれば、成功するはずだ。

npm test

ブラウザで画面遷移を確認してみよう。

http://localhost:3000で見た3つのパス

最後に、スタイルも追加しよう。入れ子構造が使えるSCSSの方が整理しやすいので、SCSSを可能にするライブラリをインストールしよう。

npm install --save node-sass

App.cssからApp.scssにリネームしてスタイルを充ててみよう。

/src/App.scss

これでApp.scssをApp.jsにimportしてから

/src/App.js

ブラウザを確認すると、

http://localhost:3000

スタイルが反映されている。ナイス!

それでは、Home画面を本格的に作っていこう。

Home 画面作成

とりあえずsrcディレクトリの中にReactのコンポーネントを入れるComponentディレクトリを作って、その中にHome画面に関連するHomePageディレクトリを作り、HomePage.js、HomePage.scss、HomePage.test.jsの空ファイルを入れてあげよう。

cd src
mkdir -p Component/HomePage
cd Component/HomePage
touch HomePage.js HomePage.scss HomePage.test.js
cd ../../..

まずHomePage.test.jsを書いてみよう。以前書いたApp.test.jsに内容の近いテストだ。

/src/Component/HomePage/HomePage.test.js
npm test

でテストを走らせると失敗するので、成功させるための実装をする。

src/Component/HomePage/HomePage.js

それをApp.jsにimportすれば、全てのテストが通るはずだ。

/src/App.js

次にGroupsの一覧が表示されることをテストしよう。

複雑なテストになるので2つのステップに分けて考えよう。

  • ① 画面表示と同時にApiリクエストを実行
  • ② 取得できたGroups一覧を表示

①に関しては、React HooksのuseEffectを使えばコンポーネントのロード時にリクエストを実行することができる。Repository Patternを使って、Groups一覧のPromiseを取得できるGroupRepoクラスが存在することを前提とすればテストが書き易くなる。

②に関しては、①が成功するまで表示内容の確認ができないので、非同期処理をの同期的に書くためのasync awaitを使う。

テストを書く前に、Groupのデータクラスを定義しよう。

mkdir src/Domain

API側で定義されているGroupと一致することが重要だ。

src/Domain/Group.js

テストファイルのテストの下に、上記①の説明で書いたGroupRepoを定義しよう。テスト用の決まったデータを扱うテストダブルなので、StubGroupRepoと呼ぶ。

src/Home/HomePage.test.js

StubGroupRepoとasync/awaitを使えばこの様なテストが書ける。HomePageをrenderする時に、StubGroupRepoを依存注入しているのが分かる。

テストが通るように実装をしよう。

src/Home/HomePage.js

React Hooksにまつわるロジックを上から説明すると、

const [group, setGroups] = useState([])

ReactのuseState Hookを利用してgroupという変数を定義し、デフォルト値を空配列にしている。

useEffect(() => {
props.groupRepo.getList()
.then(groups => setGroups(groups))
}, [props.groupRepo])

レンダー時に実行されるuseEffect Hookを利用。props経由で依存注入されたgroupRepoのgetList()を呼び、戻ってきたgroupsを先ほど定義した変数groupにセットする。最後に、再実行の条件として依存している変数を配列に追加すれば、変更があった場合useEffectが再実行される。

これでhomePage.test.jsのテストはパスするはずだが、App.test.jsが失敗する。理由を見てみると、

HomePage.test.jsではStubGroupRepoを注入しているが、 App.test.jsでは注入できていないので失敗する。

ようやく「本物」のGroupRepoを作成する必要ができた。

mkdir src/Repo

テストで定義したSpyGroupRepoと同じメソッドを追加しよう。

src/Repo/GroupRepo.js

これでテストは通るはずだ。

次に、空配列ではなくAPIリクエストとJSON処理の実装を追加したい。テストから書いてみよう。

/src/Repo/GroupRepo.test.js
/src/Repo/browserWrapper.js
/src/Repo/GroupRepo.js

fetchをWrapperオブジェクトで包んで、それをSpyとして注入すれば、テストも実装もスムーズにいく。

これで画面を表示すると、PhoenixのAPIで作成したGroupsが表示される!

最後に画面遷移のテストを追加しよう。

データ取得の時と同様、外部(別コンポーネント)との連携なので、別クラス(redirectService)にロジックをまかせて依存注入しよう。

あとは実装すれば必要な機能が揃うはず。

RedirectServiceを依存注入するためには、App.jsでRedirectServiceを初期化する必要がある。<BrowserRouter/><Router history={createBrowserHistory()}/>と置き換えれば、

/src/App.js

そのhistoryを使ってhistory.push(route)で画面遷移できる。

/src/Service/RedirectService.js

あとはHomePageから呼び出すだけ。

/src/HomePage/HomePage.js

これでHome Pageができた!

ここまでのコードはP2_1_HOME_PAGE参照。

スタイルガイド作成

ページ間で使える共通のスタイルを追加。

🚧(このセクション、作成中。。。)

ここまでのコードはP2_2_STYLE_GUIDE参照。

Group詳細画面作成

APIから取得したメッセージ一覧を表示。

🚧(このセクション、作成中。。。)

ここまでのコードはP2_3_GROUP_DETAIL_PAGE参照。

Group作成画面作成

APIへのPOSTリクエストでGroupを新規作成。

🚧(このセクション、作成中。。。)

ここまでのコードはP2_4_NEW_GROUP_PAGE参照。

--

--