Routage Client (utilisant react-router) et routage Côté Serveur

j'ai réfléchi et je suis confus avec le routage entre le Client et le serveur. Supposons que J'utilise ReactJS pour le rendu côté serveur avant de renvoyer la requête au navigateur web, et que j'utilise react-router comme routage côté client pour passer d'une page à l'autre sans rafraîchir en tant que SPA.

ce qui vient à l'esprit est:

  • comment les itinéraires sont-ils interprétés? Par exemple, une requête de la page D'accueil ( /home ) à la page des Posts ( /posts )
  • où va le routage, côté serveur ou client?
  • Comment sait-elle comment elle est traitée?
100
demandé sur Kenny John Jacob 2015-02-17 05:51:59

2 réponses

Note, Cette réponse couvre la version 0.13 du routeur React.x - la version à venir 1.0 semble avoir des détails de mise en œuvre très différents

Serveur

c'est un minimum server.js avec routeur react:

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})
  })
})

où le module routes exporte une liste de Routes:

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

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

Chaque fois qu'un la requête est faite au serveur, vous créez une instance à usage unique Router configurée avec L'URL entrante comme sa position statique, qui est résolue par rapport à l'arbre des routes pour configurer les routes correspondantes appropriées, appelant avec le gestionnaire de route de haut niveau à rendre et un enregistrement de quelles routes enfants correspondent à chaque niveau. C'est ce qui est consulté lorsque vous utilisez le composant <RouteHandler> dans un composant de gestion de route pour rendre une route enfant qui a été appariée.

si L'Utilisateur a désactivé JavaScript, ou s'il est lent à charger, tout lien sur lequel il clique va frapper le serveur à nouveau, ce qui est résolu à nouveau comme ci-dessus.

Client

minimale client.js avec réagissent-routeur (ré-utiliser les mêmes voies 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)
})

quand vous appelez Router.run() , il crée une instance de routeur pour vous dans les coulisses, qui est réutilisé à chaque fois que vous naviguez app, comme L'URL peut être dynamique sur le client, par opposition à sur le serveur où une seule requête a une URL fixe.

dans ce cas, nous utilisons le HistoryLocation , qui utilise le History API pour s'assurer que la bonne chose se produit lorsque vous appuyez sur le bouton back/forward. Il y a aussi un HashLocation qui change L'URL hash pour faire des entrées d'histoire et écoute l'événement window.onhashchange pour déclencher navigation.

lorsque vous utilisez le composant <Link> de react-router, vous lui donnez un to prop qui est le nom d'une route, plus toutes les données params et query dont la route a besoin. Le <a> rendu par ce composant a un handler onClick qui finalement appelle router.transitionTo() sur l'instance du routeur avec les accessoires que vous avez donné le lien, qui ressemble à ceci:

  /**
   * 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);
    }
  },

pour un lien régulier ce appelle location.push() sur le type D'emplacement que vous utilisez, qui gère les détails de configuration de l'historique de sorte que la navigation avec les boutons back et forward fonctionnera, puis rappelle à router.handleLocationChange() pour faire savoir au routeur qu'il peut procéder à la transition vers le nouveau chemin D'URL.

le routeur appelle alors sa propre méthode router.dispatch() avec la nouvelle URL, qui gère les détails de déterminer quelles routes configurées correspondent à L'URL, puis appelle toute crochets de transition présents pour les routes appariées. Vous pouvez mettre en œuvre ces crochets de transition sur n'importe lequel de vos gestionnaires de route pour prendre des mesures quand une route est sur le point d'être naviguée loin de ou vers, avec la possibilité d'avorter la transition si les choses ne sont pas à votre goût.

si la transition n'a pas été interrompue, l'étape finale est d'appeler le rappel que vous avez donné à Router.run() avec le composant de handler de haut niveau et un objet d'état avec tous les détails de L'URL et des routes correspondantes. Le composant de gestionnaire de niveau supérieur est en fait l'instance Router elle-même, qui gère le rendu du gestionnaire de route le plus élevé qui a été apparié.

le processus ci-dessus est relancé chaque fois que vous naviguez vers une nouvelle URL sur le client.

exemples de projets

130
répondu Jonny Buchanan 2015-05-11 21:59:13

avec 1.0, React-Router dépend du module history en tant que peerDependency. Ce module traite du routage dans le navigateur. Par défaut, React-Router utilise L'API D'historique HTML5( pushState , replaceState ), mais vous pouvez le configurer pour utiliser le routage basé sur le hachage (voir ci-dessous)

la manipulation de l'itinéraire se fait maintenant en coulisse, et Reactor envoie de nouveaux accessoires aux gestionnaires de L'itinéraire lorsque l'itinéraire change. Le routeur a un nouveau onUpdate prop callback toutes les fois qu'une route change, utile pour le suivi de pageview, ou la mise à jour du <title> , par exemple.

Client (routage 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)

Client (routage basé sur le hachage)

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)

Serveur

sur le serveur, nous pouvons utiliser ReactRouter.match , ceci est tiré du guide de rendu de serveur

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')
    }
  })
})
25
répondu tom 2018-02-20 08:12:09