首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >客户端路由(使用react-router)和服务器端路由

客户端路由(使用react-router)和服务器端路由
EN

Stack Overflow用户
提问于 2015-02-17 10:51:59
回答 2查看 76.1K关注 0票数 112

我一直在思考,我对客户端和服务器之间的路由感到困惑。假设在将请求发送回web浏览器之前,我使用ReactJS进行服务器端渲染,并使用react-router作为客户端路由在页面之间切换,而无需刷新。

脑海中浮现的是:

  • 如何解释这些路由?例如,从主页(/home)到Posts页(/posts)
  • Where的请求是在服务器端还是在客户端进行路由?
  • 它如何知道如何处理它?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-02-17 17:25:22

请注意,此答案涵盖React路由器版本0.13.x - 看起来将具有显著不同的实施细节

服务器

这是一个带有react- server.js的最小路由器:

代码语言:javascript
复制
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模块导出路由列表:

代码语言:javascript
复制
var React = require('react')
var {DefaultRoute, NotFoundRoute, Route} = require('react-router')

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

每次向服务器发出请求时,您都会创建一个Router实例,该实例使用传入的URL配置为其静态位置,该实例根据路由树进行解析,以设置适当的匹配路由,并使用要呈现的顶级路由处理程序进行回调,并记录每个级别上匹配的子路由。这就是在路由处理组件中使用<RouteHandler>组件来呈现匹配的子路由时要参考的内容。

如果用户关闭了JavaScript,或者加载速度很慢,他们点击的任何链接都会再次命中服务器,如上所述再次解决。

客户端

这是一个带有react- client.js的最小路由(重用相同的路由模块):

代码语言:javascript
复制
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来确保当您点击back/forward按钮时发生正确的事情。还有一个HashLocation,它更改URL hash以创建历史条目,并侦听window.onhashchange事件以触发导航。

当您使用react-router的<Link>组件时,您将为它提供一个to属性,这是一个路由的名称,外加该路由所需的任何paramsquery数据。此组件呈现的<a>有一个onClick处理程序,该处理程序最终使用您提供的链接属性调用路由器实例上的router.transitionTo(),如下所示:

代码语言:javascript
复制
  /**
   * 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时,都会重新运行上述过程。

示例项目

票数 139
EN

Stack Overflow用户

发布于 2015-11-13 04:01:45

在1.0中,React-Router依赖于history模块作为peerDependency。此模块处理浏览器中的路由。默认情况下,React-Router使用HTML5历史API (pushStatereplaceState),但您可以将其配置为使用基于散列的路由(见下文)

路由处理现在是在幕后完成的,当路由更改时,ReactRouter会向路由处理程序发送新的道具。每当路由改变时,路由器都有一个新的onUpdate属性回调,例如,对于页面查看跟踪或更新<title>很有用。

客户端(HTML5路由)

代码语言:javascript
复制
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)

客户端(基于哈希的路由)

代码语言:javascript
复制
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)

服务器

在服务器上,我们可以使用取自server rendering guideReactRouter.match

代码语言:javascript
复制
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')
    }
  })
})
票数 26
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28553904

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档