客户端路由(使用 react-router)和服务器端路由 [英] Client Routing (using react-router) and Server-Side Routing

查看:43
本文介绍了客户端路由(使用 react-router)和服务器端路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have been thinking and I am confused with the routing between Client and Server. Suppose I use ReactJS for server-side rendering before sending the request back to web browser, and use react-router as a client-side routing to switch between pages without refreshing as SPA.

想到的是:

  • 如何解释路由?例如,从主页 (/home) 到帖子页面 (/posts) 的请求
  • 路由去哪里了,在服务器端还是客户端?
  • 它如何知道它是如何处理的?
  • How are the routes interpreted? For example, a request from Home page (/home) to Posts page (/posts)
  • Where does the routing go, on server-side or client?
  • How does it know how it is processed?

推荐答案

注意,这个答案涵盖 React Router 版本 0.13.x - 即将发布的 1.0 版 看起来将有显着不同的实现细节

Note, this answer covers React Router version 0.13.x - the upcoming version 1.0 looks like it will have significantly different implementation details

这是一个带有 react-router 的最小 server.js:

This is a minimal server.js with react-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 模块导出路由列表的地方:

Where the routes module exports a list of Routes:

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

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

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

Every time a request is made to the server, you create a single-use Router instance configured with the incoming URL as its static location, which is resolved against the tree of routes to set up the appropriate matched routes, calling back with the top-level route handler to be rendered and a record of which child routes matched at each level. This is what's consulted when you use the <RouteHandler> component within a route handling component to render a child route which was matched.

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

If the user has JavaScript turned off, or it's being slow to load, any links they click on will hit the server again, which is resolved again as above.

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

This is a minimal client.js with react-router (re-using the same routes module):

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 的服务器上.

When you call Router.run(), it creates a Router instance for you behind the scenes, which is re-used every time you navigate around the app, as the URL can be dynamic on the client, as opposed to on the server where a single request has a fixed URL.

在本例中,我们使用 HistoryLocation,它使用 History API 以确保在您点击后退/前进按钮时发生正确的事情.还有一个 HashLocation 可以更改 URL hash 以创建历史条目并监听 window.onhashchange 触发导航的事件.

In this case, we're using the HistoryLocation, which uses the History API to make sure the right thing happens when you hit the back/forward button. There's also a HashLocation which changes the URL hash to make history entries and listens to the window.onhashchange event to trigger navigation.

当你使用 react-router 的 组件时,你给它一个 to 属性,它是路由的名称,加上任何 paramsquery 路由需要的数据.此组件呈现的 有一个 onClick 处理程序,它最终会使用您的道具在路由器实例上调用 router.transitionTo()给了链接,看起来像这样:

When you use react-router's <Link> component, you give it a to prop which is the name of a route, plus any params and query data the route needs. The <a> rendered by this component has an onClick handler which ultimately calls router.transitionTo() on the router instance with the props you gave the link, which looks like this:

  /**
   * 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 路径.

For a regular link this ultimately calls location.push() on whichever Location type you're using, which handles the details of setting up history so navigating with the back and forward buttons will work, then calls back to router.handleLocationChange() to let the router know it can proceed with transitioning to the new URL path.

路由器然后使用新的 URL 调用自己的 router.dispatch() 方法,该方法处理确定哪些配置的路由与 URL 匹配的细节,然后调用任何 transition hooks 存在于匹配的路由中.您可以在任何路由处理程序上实现这些转换钩子,以便在路由即将离开或导航到时采取一些操作,如果事情不符合您的喜好,可以中止转换.

The router then calls its own router.dispatch() method with the new URL, which handles the details of determining which of the configured routes match the URL, then calls any transition hooks present for the matched routes. You can implement these transition hooks on any of your route handlers to take some action when a route is about to be navigated away from or navigated to, with the ability to abort the transition if things aren't to your liking.

如果转换没有中止,最后一步是使用顶级处理程序组件和包含所有详细信息的状态对象调用您提供给 Router.run() 的回调URL 和匹配的路由.顶级处理程序组件实际上是 Router 实例本身,它处理渲染匹配的最顶级路由处理程序.

If the transition wasn't aborted, the final step is to call the callback you gave to Router.run() with the top-level handler component and a state object with all the details of the URL and the matched routes. The top-level handler component is actually the Router instance itself, which handles rendering the top-most route handler which was matched.

每次导航到客户端上的新 URL 时,都会重新运行上述过程.

The above process is re-run every time you navigate to a new URL on the client.

这篇关于客户端路由(使用 react-router)和服务器端路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆