クライアントルーティング(react-routerを使用)およびサーバー側ルーティング


108

私は考えていましたが、クライアントとサーバー間のルーティングに戸惑っています。Webブラウザーにリクエストを送信する前にサーバー側のレンダリングにReactJSを使用し、SPAとして更新することなくページを切り替えるクライアント側のルーティングとしてreact-routerを使用するとします。

頭に浮かぶのは:

  • ルートはどのように解釈されますか?たとえば、ホームページ(/home)から投稿ページ(/posts)へのリクエスト
  • サーバー側またはクライアント上のルーティングはどこに行きますか?
  • それがどのように処理されるかはどのようにしてわかりますか?

1
ブラウザでHistory APIを読むことをお勧めします。
WiredPrairie、2015

回答:


137

この回答はReact Routerバージョン0.13.xをカバーしています- 次のバージョン1.0は実装の詳細が大幅に異なるようです

サーバ

これは、server.jsreact-routerを使用した最小限のものです。

var express = require('express')
var React = require('react')
var Router = require('react-router')

var routes = require('./routes')

var app = express()

// ...express config...

app.use(function(req, res, next) {
  var router = Router.create({location: req.url, routes: routes})
  router.run(function(Handler, state) {
    var html = React.renderToString(<Handler/>)
    return res.render('react_page', {html: html})
  })
})

routesモジュールがルートのリストをエクスポートする場所:

var React = require('react')
var {DefaultRoute, NotFoundRoute, Route} = require('react-router')

module.exports = [
  <Route path="/" handler={require('./components/App')}>
    {/* ... */}
  </Route>
]

サーバーにリクエストが送信されるたびにRouter、静的URLとして受信URLを使用して構成された使い捨てインスタンスを作成します。これはルートのツリーに対して解決され、適切な一致するルートを設定し、トップレベルでコールバックしますレンダリングされるルートハンドラーと、各レベルで一致した子ルートのレコード。これは<RouteHandler>、ルート処理コンポーネント内のコンポーネントを使用して、一致した子ルートをレンダリングするときに参照されるものです。

ユーザーがJavaScriptをオフにしている場合、またはJavaScriptの読み込みが遅い場合、ユーザーがクリックしたリンクは再びサーバーにヒットします。これは上記のように再度解決されます。

クライアント

これは、client.jsreact-routerを使用した最小限のものです(同じルートモジュールを再利用します)。

var React = require('react')
var Router = require('react-router')

var routes = require('./routes')

Router.run(routes, Router.HistoryLocation, function(Handler, state) {
  React.render(<Handler/>, document.body)
})

を呼び出すとRouter.run()、バックグラウンドでルーターインスタンスが作成されます。これは、アプリ内を移動するたびに再利用されます。これは、単一のリクエストがあるサーバー上ではなく、クライアント上でURLが動的になる可能性があるためです。固定URL。

この例ではHistoryLocation、を使用していHistoryます。これは、APIを使用して、戻る/進むボタンを押したときに正しい動作が行われることを確認します。ありますHashLocationURLを変更するhashには履歴エントリとリッスンを作るためにwindow.onhashchange、トリガ・ナビゲーションへのイベント。

react-routerの<Link>コンポーネントを使用する場合toは、ルートの名前であるpropと、ルートが必要paramsqueryするすべてのデータを提供します。<a>このコンポーネントによってレンダリングがありonClick、最終的に呼び出すハンドラrouter.transitionTo()あなたはこのようになりますリンクを、与えた小道具を持つルータインスタンス上を:

  /**
   * Transitions to the URL specified in the arguments by pushing
   * a new URL onto the history stack.
   */
  transitionTo: function (to, params, query) {
    var path = this.makePath(to, params, query);

    if (pendingTransition) {
      // Replace so pending location does not stay in history.
      location.replace(path);
    } else {
      location.push(path);
    }
  },

通常のリンクの場合、これは最終的にlocation.push()、使用している場所の種類を呼び出します。これは、履歴の設定の詳細を処理するため、[戻る]ボタンと[進む]ボタンを使用したナビゲーションが機能し、次にに呼び出してrouter.handleLocationChange()、ルーターが新しいURLパス。

次に、ルーターrouter.dispatch()は新しいURLを使用して独自のメソッドを呼び出します。これは、構成されたルートのどれがURLと一致するかを決定する詳細を処理し、一致したルートに存在する遷移フックを呼び出します。これらの遷移フックを任意のルートハンドラーに実装して、ルートが別の場所に移動したり、別の場所に移動したりするときにアクションを実行できます。必要に応じて遷移を中止することもできます。

移行が中止されなかった場合、最後のステップはRouter.run()、トップレベルのハンドラコンポーネントと、URLと一致したルートのすべての詳細を含む状態オブジェクトを使用して、コールバックを呼び出すことです。最上位のハンドラコンポーネントは実際にはRouterインスタンス自体であり、一致した最上位のルートハンドラのレンダリングを処理します。

上記のプロセスは、クライアントで新しいURLに移動するたびに再実行されます。

プロジェクトの例


3
したがって、クライアントルーティングは、存在する場合、JavaScript(react-routerコード)によって処理されると言えるでしょう。ブラウザのアドレスバーでEnterキーを押すか、ページを更新するか、JSを無効にすると、サーバー側がルーティングを処理します。一方、現在のページでJavaScriptの準備ができている場合、ルーティングはクライアント側で処理されます。私は正しく理解しましたか?
ハートモン2015

9
ルートモジュールにvar routes = require('./routes')は何がありますか?それはルートのリストですか?私はエクスプレスルーターを使用しましたが、このSOのこの例は、Reactルーターでサーバー側レンダリングを設定する唯一の例のようです。そのため、完全なコード例であるとよいでしょう
svnm

2
ルートのリストである必要があります。それに関するメモとサンプルプロジェクトへのリンクを追加します。
ジョニーブキャナン

2
では、react-routerがサーバー側のルーティングを処理する場合、データベースと対話するのはだれですか。サーバー側のルーティングはどうなりますか?ネイティブモバイルアプリにREST APIを提供したいとします。誰がそれを処理しますか?
Morteza Shahriari Nia

1
新しいreact-routerバージョンのため、回答は古くなっています。更新してください。
oleh.meleshko

26

1.0では、React-Routerは、peerDependencyとして履歴モジュールに依存しています。このモジュールは、ブラウザでのルーティングを扱います。デフォルトでは、React-RouterはHTML5 History API(pushStatereplaceState)を使用しますが、ハッシュベースのルーティングを使用するように構成できます(以下を参照)。

ルートの処理はバックグラウンドで行われるようになり、ルートが変更されると、ReactRouterは新しいハンドラーをルートハンドラーに送信します。ルーターには、onUpdateルートが変更されるたびに新しいpropコールバックがあり、ページビューの追跡やの更新などに役立ち<title>ます。

クライアント(HTML5ルーティング)

import {Router} from 'react-router'
import routes from './routes'

var el = document.getElementById('root')

function track(){
  // ...
}

// routes can be children
render(<Router onUpdate={track}>{routes}</Router>, el)

クライアント(ハッシュベースのルーティング)

import {Router} from 'react-router'
import {createHashHistory} from 'history'
import routes from './routes'

var el = document.getElementById('root')

var history = createHashHistory()

// or routes can be a prop
render(<Router routes={routes} history={history}></Router>, el)

サーバ

サーバーではを使用できますReactRouter.match。これはサーバーレンダリングガイドから取得されます

import { renderToString } from 'react-dom/server'
import { match, RoutingContext } from 'react-router'
import routes from './routes'

app.get('*', function(req, res) {
  // Note that req.url here should be the full URL path from
  // the original request, including the query string.
  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    if (error) {
      res.status(500).send(error.message)
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search)
    } else if (renderProps) {
      res.status(200).send(renderToString(<RoutingContext {...renderProps} />))
    } else {
      res.status(404).send('Not found')
    }
  })
})
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.