私は考えていましたが、クライアントとサーバー間のルーティングと混同しています。 Webブラウザにリクエストを送信する前にサーバー側のレンダリングにReactJSを使用し、クライアント側のルーティングとして反応ルーターを使用して、SPAとして更新せずにページを切り替えると仮定します。
頭に浮かぶのは:
/home
)から投稿ページ(/posts
)へのリクエスト、この回答はReactルーターバージョン0.13.xを対象としています- 次のバージョン1. は実装の詳細が大幅に異なるようです
これは、react-routerを備えた最小限のserver.js
です:
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>
]
サーバーにリクエストが行われるたびに、着信URLを静的な場所として構成されたシングルユースRouter
インスタンスを作成します。これは、ルートツリーに対して解決され、適切な一致ルートをセットアップして、コールバックしますレンダリングされる最上位のルートハンドラと、各レベルで一致した子ルートのレコードを使用します。これは、ルート処理コンポーネント内で<RouteHandler>
コンポーネントを使用して、一致した子ルートをレンダリングするときに参照されるものです。
ユーザーがJavaScriptをオフにしている場合、またはロードが遅い場合、クリックしたリンクは再びサーバーにヒットします。これは上記のように再び解決されます。
これは、react-routerを使用した最小のclient.js
です(同じルートモジュールを再利用):
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 を使用して、戻る/進むボタンを押したときに正しいことを確認します。 URLを変更するHashLocation
もありますhash
履歴エントリを作成し、ナビゲーションをトリガーするために window.onhashchange
イベントをリッスンします。
React-routerの<Link>
コンポーネントを使用する場合、ルートの名前であるto
propに加えて、ルートに必要なparams
およびquery
データを指定します。このコンポーネントによってレンダリングされる<a>
には、最終的にルーターインスタンスでrouter.transitionTo()
を呼び出すonClick
ハンドラーがあります。
/**
* 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パスへの移行。
次に、ルーターは新しいURLで独自のrouter.dispatch()
メソッドを呼び出します。このメソッドは、構成されたルートのいずれがURLと一致するかを決定する詳細を処理し、一致したルートに存在する transition hooks を呼び出します。これらのトランジションフックをルートハンドラーに実装して、ルートが近づいたり近づいたりするときにアクションを実行し、好みに合わない場合にトランジションを中止することができます。
遷移が中断されなかった場合、最後のステップは、Router.run()
に指定したコールバックを、トップレベルハンドラーコンポーネントと、URLと一致したルートのすべての詳細を含む状態オブジェクトで呼び出すことです。最上位のハンドラーコンポーネントは、実際にはRouter
インスタンスそのものであり、一致した最上位のルートハンドラーのレンダリングを処理します。
上記のプロセスは、クライアントで新しいURLに移動するたびに再実行されます。
1.0では、React-Routerは、peerDependencyとして history モジュールに依存します。このモジュールは、ブラウザでのルーティングを扱います。デフォルトでは、React-RouterはHTML5 History API(pushState
、replaceState
)を使用しますが、ハッシュベースのルーティングを使用するように設定できます(以下を参照)
これで、ルートの処理はバックグラウンドで行われ、ReactRouterはルートが変更されると新しい小道具をルートハンドラーに送信します。ルーターには、ルートが変更されるたびに新しいonUpdate
propコールバックがあり、ページビューの追跡、または<title>
の更新などに役立ちます。
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')
}
})
})