reactjs - react - En la arquitectura Flux, ¿cómo gestiona los estados de enrutamiento/url del lado del cliente?
react tutorial 2018 español (2)
La mayoría de los ejemplos en la naturaleza hacen uso de React Router , un marco basado en el enrutador Ember. La parte importante es la configuración de las rutas como especificación declarativa de los componentes:
React.render((
<Router>
<Route path="/" component={App}>
<Route path="about" component={About}/>
<Route path="users" component={Users}>
<Route path="/user/:userId" component={User}/>
</Route>
<Redirect from="/" to="about" />
<NotFoundRoute handler={NoMatch} />
</Route>
</Router>
), document.body)
Como seguimiento de la pregunta del ciclo de vida de la tienda ,
En una aplicación web típica es bueno tener un acceso directo al estado actual de la aplicación a través de la URL para que pueda volver a visitar ese estado y usar los botones de avance y retroceso para moverse entre estados.
Con Flux queremos que todas las acciones pasen por el despachador, lo que supongo también incluye un cambio de URL. ¿cómo gestionaría los cambios de URL dentro de una aplicación de flujo?
[Actualizar]
Después de trabajar en un montón de aplicaciones de React / Flux, he llegado a la conclusión de que prefiero que el enrutamiento se maneje por separado y de forma ortogonal al flujo. La estrategia es que las URL / rutas determinen qué componentes se montan, y los componentes solicitan datos de las tiendas en función de los parámetros de la ruta y otros estados de la aplicación según sea necesario.
[Respuesta original]
Un enfoque que tomé con un proyecto reciente mientras experimentaba con Flux fue convertir la capa de enrutamiento en otra tienda. Esto significa que todos los enlaces que cambian la URL en realidad activan una acción a través del despachante solicitando que la ruta se actualice. Un RouteStore
respondió a este envío configurando la URL en el navegador y configurando algunos datos internos (a través route-recognizer ) para que las vistas pudieran consultar los nuevos datos de enrutamiento cuando el evento de change
se activa desde la tienda.
Una pieza no obvia para mí fue cómo asegurar las acciones desencadenadas por los cambios de URL; Terminé creando una mezcla para administrar esto para mí (nota: esto no es 100% robusto, pero funcionó para la aplicación que estaba usando, puede que tenga que hacer modificaciones para satisfacer sus necesidades).
// Mix-in to the top-level component to capture `click`
// events on all links and turn them into action dispatches;
// also manage HTML5 history via pushState/popState
var RoutingMixin = {
componentDidMount: function() {
// Some browsers have some weirdness with firing an extra ''popState''
// right when the page loads
var firstPopState = true;
// Intercept all bubbled click events on the app''s element
this.getDOMNode().addEventListener(''click'', this._handleRouteClick);
window.onpopstate = function(e) {
if (firstPopState) {
firstPopState = false;
return;
}
var path = document.location.toString().replace(document.location.origin, '''');
this.handleRouteChange(path, true);
}.bind(this);
},
componentWillUnmount: function() {
this.getDOMNode().removeEventListener(''click'', this._handleRouteClick);
window.onpopstate = null;
},
_handleRouteClick: function(e) {
var target = e.target;
// figure out if we clicked on an `a` tag
while(target && target.tagName !== ''A'') {
target = target.parentNode;
}
if (!target) return;
// if the user was holding a modifier key, don''t intercept
if (!e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey) {
e.preventDefault();
var href = target.attributes.href.value;
this.handleRouteChange(href, false);
}
}
};
Se usaría como tal:
var ApplicationView = React.createClass({
mixins: [RoutingMixin],
handleRouteChange: function(newUrl, fromHistory) {
this.dispatcher.dispatch(RouteActions.changeUrl(newUrl, fromHistory));
},
// ...
});
El controlador en la tienda puede verse algo así como:
RouteStore.prototype.handleChangeUrl = function(href, skipHistory) {
var isFullUrl = function(url) {
return url.indexOf(''http://'') === 0 || url.indexOf(''https://'') === 0;
}
// links with a protocol simply change the location
if (isFullUrl(href)) {
document.location = href;
} else {
// this._router is a route-recognizer instance
var results = this._router.recognize(href);
if (results && results.length) {
var route = results[0].handler(href, results[0].params);
this.currentRoute = route;
if (!skipHistory) history.pushState(href, '''', href);
}
this.emit("change");
}
}