抹桥的博客
Language
Home
Archive
About
GitHub
Language
主题色
250
1830 文字
9 分
React ベースのフロントエンドプロジェクト開発まとめ

技術選定#

私たちのプロジェクトは、主に以下の技術といくつかの補助ツールを使用して開発されています。

  • react
  • react-router
  • redux
  • react-redux

開発およびオンライン環境#

開発環境#

プロジェクトはフロントエンドとバックエンドが分離されているため、以下の機能を含む完全な開発環境が必要です。

  • データモック
  • Webpackによるコンパイルとホットリロード
  • フロントエンドとバックエンドの連携デバッグの容易さ

これらの要件に基づき、Express、Webpack、Webpack-dev-middleware を使用して、この完全な開発環境を構築しました。

開発環境

ご覧の通り、ブラウザからのすべてのリクエストはローカルのNode.jsサービスによってインターセプトされます。静的リソースのリクエストは webpack-dev-middleware に委譲され、APIリクエストは異なる環境に応じて処理が決定されます。

ローカル開発#

ENV = 'development' の場合、つまり開発環境では、ローカルのモックデータを直接読み込んでページをレンダリングします。

フロントエンドとバックエンドの連携デバッグ#

ENV = 'api' の場合、つまり連携デバッグ環境では、APIリクエストはNode.jsによって連携デバッグが必要な実際のバックエンドサービスアドレスに転送され、直接呼び出しによって発生するクロスオリジン問題を回避します。

これにより、ローカルの開発コードで直接バックエンドと連携デバッグを行うことができ、効率が大幅に向上し、毎回サーバーにビルドしてデプロイする手間が省けます。

オンライン環境#

フロントエンドとバックエンドは別々にデプロイされており、すべての静的リソースはCDN (example.cdn.com)上に配置されています。

つまり、私たちのページは example.cdn/index.html にありますが、リクエストされるAPIは example.163.com/api/xxx にあります。ユーザーに直接 example.cdn.com/index.html にアクセスさせることは不合理であり、クロスオリジン問題も存在します。

では、example.dai.163.com にアクセスした際に、どのようにしてHTMLページを取得するのでしょうか? 以下の図をご覧ください。

オンライン環境

クライアントとバックエンドサービス間にNginxを設置します。example.dai.163.com へのアクセスには2種類のリクエストがあります。

  • HTMLページリソース
  • APIリクエスト

これらの2種類のリクエストはどちらもまずNginxを経由し、ここで判断が行われます。ページリクエストであればNginxがCDNに転送し、そうでなければバックエンドサービスがAPIリクエストに応答します。

ページを取得した後、その他のすべてのCSS、JSなどの静的リソースは直接CDNにリクエストされます。ここについては特に説明することはありません。

データフロー#

Reduxを活用してデータフローを管理します。この図をご覧ください。

データフロー

まず、middlewarereducer を通じて store が生成され、プロジェクトの初期 state が取得されます。この初期 state を使用してページの初期状態がレンダリングされます。

Home ページを例にとると、まず Homereact-redux が提供する connect メソッドを通じて初期 state を取得し、それを Homeprop として Home に渡します。Home は複数の異なる子コンポーネントで構成されており、これらのコンポーネントが必要とするデータは、さらに Home から props を介して自身の子コンポーネントに渡されます。

Home の初期状態のロードが完了した後、ユーザーデータを取得するためにバックエンドにリクエストを送信する必要があります。このとき、以下の形式の action をディスパッチします。

{
  types: ['home/start','home/success','home/failure'],
  payload: {
    api:
    ...
  },
  meta: {
    isApi: true
  }
}

すべての action は、私たちが定めた順序で一つ一つの middleware を通過します。

ここで、私たちの actioncallApiMiddleware によって meta 内の isApi フラグで識別され、それに応じた処理が行われます。

例えば、このミドルウェアでは、実際のAPIリクエストを行い、リクエストの成功または失敗時に対応する action をディスパッチし、統一されたビジネスロジックも処理します。例えば、バックエンドから返されるAPIの code 値について統一された規約があり、1が成功、2が失敗、3が未ログインであると仮定します。そうすれば、これらのビジネスロジックをミドルウェア内で処理できます。

リクエストが成功し、ページがレンダリングされた後、ユーザーがボタンをクリックしたとします。このボタンは、例えば写真撮影のような native の機能を呼び出す必要があります。このとき、写真撮影機能を呼び出す camera/start という action をディスパッチします。

{
  types: ['sdk/start','sdk/success','sdk/failure'],
  payload: {
    command:
    ...
  },
  meta: {
    isSDK: true
  }
}

同様に、この actionEpaySDKMiddleware によって認識され処理されます。ネイティブ機能を呼び出す際、セキュリティを確保するために、署名を取得するためのリクエストをバックエンドに送信する必要があります。このとき、EpaySDKMiddleware 内でAPIリクエストの action をディスパッチできます。この action もすべての middleware を通過する必要があります。すると、このAPIリクエストの action は、上記のフローと同様に callApiMiddleware を通じて処理されます。

ミドルウェアの存在により、全体のフローが非常に明確になります。APIリクエストのミドルウェアはAPIリクエストのみを行い、ネイティブAPI呼び出しのミドルウェアはネイティブ呼び出しのみを行います。ネイティブAPI呼び出しがバックエンドAPIリクエストを必要とする場合、APIリクエストのミドルウェアを通過する action をディスパッチします。

各ミドルウェアは自身の役割にのみ集中するため、その後のメンテナンスが容易になり、優れた拡張方法も提供します。View 層が行う必要があるのは、action をディスパッチし、データを受け取ってページをレンダリングすることだけであり、他のロジックについて心配する必要はありません。

#

全体フロー

以下のようなルーティング設定があると仮定します。

{
    component: App,
    path: '/',
    onEnter: initLogin(store),
    indexRoute: {
      getComponent(nextState, cb) {
        require.ensure([], require => {
          cb(null, require('../views/Home').default)
        }, 'Home')
      },
      onEnter: initHome(store)
    },
    childRoutes: [
      createActivateRoute(store),
      {
        path: 'test',
        indexRoute: {
          getComponent(nextState, cb) {
            require.ensure([], require => {
              cb(null, require('../views/Test').default)
            }, 'Test')
          }
        }
      },
      ...
    ]
}

では、react-router と組み合わせて完全なフローを見てみましょう。ブラウザに example.dai.163.com/index.html/#/ と入力したときです。

まず、冒頭の「オンライン環境」セクションで述べた内容を通じて、ページに必要なHTML、CSS、JSを取得します。

次に、Provide コンポーネントと Router コンポーネントをレンダリングし、それぞれ store の注入とルーティングの制御を提供します。

このとき、ルートパスのルーティングマッチがトリガーされ、ルートコンポーネント APP がロードされます。その後、ルーティングマッチルールに基づいて IndexRouter がマッチし、Home コンポーネントがロードされます。

その後の処理は、前述の「データフロー」セクションで説明した内容と同じです。

まとめ#

フロントエンドとバックエンドが完全に分離されていることを前提に、完全な開発環境を活用することで、開発効率を大幅に向上させ、フロントエンドとバックエンドの連携デバッグのコストを削減できます。

同時に、Reduxの思想を活用して単方向データフローを実現することで、非常に明確なデータフローを構築できます。さらに、ミドルウェアを活用することで、データフローのプロセスをより効果的に制御できます。これにより、将来のプロジェクト拡張に無限の可能性を提供します。

この記事は 2017年5月12日 に公開され、2017年5月12日 に最終更新されました。3068 日が経過しており、内容が古くなっている可能性があります。

React ベースのフロントエンドプロジェクト開発まとめ
https://blog.kisnows.com/ja-JP/2017/05/12/react-base-project-summary/
作者
Kisnows
公開日
2017-05-12
ライセンス
CC BY-NC-ND 4.0