Tenga en cuenta que esta respuesta cubre React Router versión 0.13.x: la próxima versión 1.0 parece que tendrá detalles de implementación significativamente diferentes
Servidor
Este es un mínimo server.js
con 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})
})
})
Donde el routes
módulo exporta una lista de Rutas:
var React = require('react')
var {DefaultRoute, NotFoundRoute, Route} = require('react-router')
module.exports = [
<Route path="/" handler={require('./components/App')}>
{/* ... */}
</Route>
]
Cada vez que se realiza una solicitud al servidor, crea una Router
instancia de un solo uso configurada con la URL entrante como su ubicación estática, que se resuelve contra el árbol de rutas para configurar las rutas coincidentes adecuadas, llamando con el nivel superior controlador de ruta que se va a representar y un registro de las rutas secundarias que coinciden en cada nivel. Esto es lo que se consulta cuando usa el <RouteHandler>
componente dentro de un componente de manejo de ruta para representar una ruta secundaria que coincidió.
Si el usuario tiene JavaScript desactivado, o si se carga con lentitud, cualquier enlace en el que haga clic llegará al servidor nuevamente, lo que se resuelve nuevamente como se indicó anteriormente.
Cliente
Este es un mínimo client.js
con react-router (reutilizando el mismo módulo de rutas):
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)
})
Cuando llama Router.run()
, crea una instancia de enrutador detrás de escena, que se reutiliza cada vez que navega por la aplicación, ya que la URL puede ser dinámica en el cliente, a diferencia de en el servidor donde una sola solicitud tiene un URL fija.
En este caso, estamos usando HistoryLocation
, que usa la History
API para asegurarse de que suceda lo correcto cuando presiona el botón Atrás / Adelante. También hay una HashLocation
que cambia la URL hash
para realizar entradas en el historial y escucha el window.onhashchange
evento para activar la navegación.
Cuando se utiliza de reaccionar-enrutador <Link>
componente, que le dan un to
puntal que es el nombre de una ruta, además de cualquier params
y query
de datos de las necesidades de ruta. El <a>
renderizado por este componente tiene un onClick
controlador que finalmente llama router.transitionTo()
a la instancia del enrutador con los accesorios que le dio al enlace, que se ve así:
/**
* 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);
}
},
Para un enlace regular, esto finalmente llama location.push()
al tipo de ubicación que esté utilizando, que maneja los detalles de la configuración del historial, por lo que la navegación con los botones de retroceso y avance funcionará, luego vuelve a llamar router.handleLocationChange()
para informar al enrutador que puede continuar con la transición a la nueva ruta de URL.
Luego, el enrutador llama a su propio router.dispatch()
método con la nueva URL, que maneja los detalles para determinar cuál de las rutas configuradas coincide con la URL, luego llama a cualquier enlace de transición presente para las rutas coincidentes. Puede implementar estos ganchos de transición en cualquiera de sus controladores de ruta para tomar alguna acción cuando una ruta esté a punto de ser navegada o alejada de ella, con la capacidad de abortar la transición si las cosas no son de su agrado.
Si la transición no se canceló, el paso final es llamar a la devolución de llamada que le dio Router.run()
con el componente de controlador de nivel superior y un objeto de estado con todos los detalles de la URL y las rutas coincidentes. El componente de controlador de nivel superior es en realidad la Router
instancia en sí, que maneja la representación del controlador de ruta más alto que se emparejó.
El proceso anterior se vuelve a ejecutar cada vez que navega a una nueva URL en el cliente.
Proyectos de ejemplo