Я думал, и я путаюсь с маршрутизацией между клиентом и сервером. Предположим, что я использую ReactJS для рендеринга на стороне сервера, прежде чем отправлять запрос обратно в веб-браузер, и использовать ретранслятор-маршрутизатор в качестве маршрутизации на стороне клиента для переключения между страницами без обновления как SPA.
Что приходит в голову:
/home
) при запросе на страницу "Почта" (/posts
)Примечание. Этот ответ охватывает версию React Router версии 0.13.x - предстоящая версия 1.0, похоже, что она будет иметь значительно разные детали реализации
Это минимальный 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>
]
Каждый раз, когда запрос отправляется на сервер, вы создаете одноразовый экземпляр Router
, настроенный с входящим URL в качестве его статического местоположения, который разрешен против дерева маршрутов для настройки соответствующих согласованных маршрутов, вызывая назад с обработчиком маршрута верхнего уровня, который будет отображаться, и запись о том, какие дочерние маршруты соответствуют каждому уровню. Это то, что было проконсультировано, когда вы используете компонент <RouteHandler>
в компоненте обработки маршрута для отображения дочернего маршрута, который был сопоставлен.
Если у пользователя отключен JavaScript или он медленно загружается, любые ссылки, на которые они нажимают, снова попадут на сервер, который будет снова разрешен, как указано выше.
Это минимальный 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()
, он создает экземпляр Router для вас за кулисами, который повторно используется при каждом перемещении по приложению, поскольку URL-адрес может быть динамическим на клиенте, а не на сервере где один запрос имеет фиксированный URL.
В этом случае мы используем HistoryLocation
, который использует History
API, чтобы убедиться, что правильная вещь случится, когда вы нажмете назад/вперед. Также существует HashLocation
, который изменяет URL hash
, чтобы сделать записи истории и прослушивать событие window.onhashchange
, чтобы вызвать навигацию.
Когда вы используете компонент response-router <Link>
, вы даете ему to
prop, который является именем маршрута, плюс любые данные params
и query
, необходимые для маршрута. <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-адресу на клиенте.
С 1.0, React-Router зависит от модуля history как peerDependency. Этот модуль касается маршрутизации в браузере. По умолчанию React-Router использует API истории HTML5 (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')
}
})
})