Isomorphic React + React Router アプリケーションで POST リクエストを処理する方法 質問する

Isomorphic React + React Router アプリケーションで POST リクエストを処理する方法 質問する

私は Isomorphic react+react-routerアプリケーションを構築したいと思っており、数日間のグーグル検索の後、GET リクエストのみを処理する Isomorphic アプリケーションを実現できるようになりました。

これまでに行ったことは次のとおりです。

  1. react-routerすべてのリクエストを処理するためにサーバーが使用される
  2. react-routerfetchDataルートに一致する各 React View に存在する関数を呼び出します。
  3. 先ほど取得したデータをReact Viewのpropsに設定し、レンダリングします。string
  4. string以前に取得したデータをグローバル変数としてHTMLに挿入しwindow.__STATE__、HTMLをクライアントに配信します。
  5. サーバーからReact Appをレンダリングすることに成功しました
  6. クライアントがReactアプリのJavaScriptの読み込みを終えると、レンダリングを試みます。しかし、window.__STATE__Reactアプリのpropsから状態を渡すと、状態が同じなのでReactは再レンダリングしません。

問題は、POST/PUT/DELETE/その他リクエストでは動作しないことです。GETリクエストを処理するときは、およびreact-routerに関する情報が必要です。たとえば、ルート: があり、クライアントがこのURL: をリクエストした場合、次のようになります。また、次のようになります。paramsquery/user/:uid/user/1?foo=barparams{uid: 1}query{foo: 'bar'}

react-router次に、それを関数に渡して、1 のfetchDataユーザーを取得し、クエリで何らかの処理を実行することを認識できるようにします。uidfoo

POST リクエストでは、react-routerPOST パラメータについてはわかりません。サーバーでは、もちろん POST パラメータをfetchData関数に渡すことができますが、クライアントはどうでしょうか? クライアントは POST パラメータが何であるかを知りません。

サーバーがクライアントに POST パラメータを通知する方法はありますか? 以下は、ログイン ビューの例です。ユーザーがフォームを送信すると、サーバーはエラーの場合はエラー メッセージを表示し、成功した場合はダッシュボードにリダイレクトするようにします。

フェッチデータ.js

import whenKeys from 'when/keys';

export default (authToken, routerState) => {
  var promises = routerState.routes.filter((match) => {
    return match.handler.fetchData;
  }).reduce((promises, match) => {
    promises[match.name] = match.handler.fetchData(authToken, routerState.params, routerState.query);
    return promises;
  }, {});

  return whenKeys.all(promises);
}

サーバー.js

...
app.use((req, res) => {
  const router = Router.create({
    routes,
    location: req.originalUrl,
    onError: next,
    onAbort: (abortReason) => {
      next(abortReason);
    }
  });

  router.run((Handler, state) => {
    fetchData(authToken, state).then((data) => {
      // render matched react View and generate the HTML
      // ...
    })
  });
});
...

ログイン.jsx

import React from 'react';
import DocumentTitle from 'react-document-title';
import api from './api';

export default class Login extends React.Component {

  constructor(props) {
    super(props);

    // how to fill this state with POST parameters on error?
    // how to redirect on success?
    // and remember that this file will be called both from server and client
    this.state = {
      error: '',
      username: '',
      password: ''
    };
  }

  // I saw some people use this function, but it'll only work if
  // the form's method is GET
  static willTransitionTo(transition, params, query) {
     // if only we could read POST parameters here
     // we could do something like this
     transition.wait(
       api.post('/doLogin', postParams).then((data) => {
         transition.redirect(`/dashboard`);
       });
     );
  }

  render() {
    return (
      <DocumentTitle title="Login">
        <div className="alert alert-danger">{this.state.error}</div>
        <form method="post">
          <input type="text" name="username" value={this.state.username}  onChange={this._onFieldChange('username')} placeholder="Username" /><br />
          <input type="password" name="password" value={this.state.password}  onChange={this._onFieldChange('password')} placeholder="Password" /><br />
          <button type="submit">Login</button>
        </form>
      </DocumentTitle>
    );
  }

  _onFieldChange(name) {
    var self = this;
    return (e) => {
      e.preventDefault();
      var nextState = {};
      nextState[name] = e.target.value;
      self.setState(nextState);
    }
  }
}

ベストアンサー1

クライアントで「POST」データを取得する

クライアント側では、フォームが正常に送信された場合にサーバー上で受信した値に対応する方法でフォーム入力から値を抽出して POST データを取得します。

POSTデータの使用

これでPOSTデータは取得できましたが、React Router 0.13.x以前のバージョンではPOSTデータをトランジションフックに取り込む方法がまだありません。そこで、この機能のプルリクエストこれは、今後の v1.0 リリースの書き直しの一部として含まれていたため、現在はクローズされています。

要点は、現在処理中のリクエスト/遷移 (この 2 つは類似しています) に関して必要な追加データを保存するための状態オブジェクトが場所に用意されるようになったことです。

  • サーバーでは、一度に1つのリクエストを処理するため、データを含む静的な場所を作成します。req.body
  • クライアントでは、状態オブジェクト (抽出されたフォーム データを含む) を に渡しますtransitionTo()

これで、トランジション フックは両方の環境で同じフォーム データを受信できるようになりました。うまくいけば素晴らしいです。うまくいかない場合は、エラーを渡してフォームを再度レンダリングする方法が必要です。ここでも新しい状態オブジェクトが役に立ちます。transition.redirect()入力データとエラーの両方を使用して渡すと、両側でレンダリングするために必要なものがすべて揃います。

v1.0 はまだベータ版であり、v0.13.x にはこれを行うために必要な API がないため、現時点ではこれ以上具体的な詳細には触れませんが、上記のプル リクエストを使用して 0.13.x でこのワークフローを実装するリポジトリがありますので、その間に参照してください。

  • 同形ラボ- README には、各要素がどのように組み合わされているかの概要が記載されています。

以下に、プロセスの大まかなフロー図をいくつか示します。

エラーと再表示を伴うサーバーPOST

サーバーフロー図

エラーと再表示を伴うクライアントPOST

クライアントフロー図


このシナリオに関連する再利用可能なモジュールもいくつか作成しました。

  • フォームデータを取得するフォームの入力から、POST された形式でデータを取得します。
  • 反応自動フォームを提供し<AutoForm>、これを の代わりに使用して、<form>フォームの入力からのすべてのデータをハンドラへの引数として受け取ることonSubmitができます。
  • 反応ルーターフォームこれは、<form>React Router のに<Link>相当します<a>。指定された への遷移をトリガーしaction、 (フォーム データ) 状態methodを渡しbodyます。これは、まもなく v1.0 に更新されます。

おすすめ記事