在Flux体系结构中,您如何pipe理客户端路由/ url状态?
作为商店生命周期问题的后续,
在典型的Web应用程序中,通过URL可以快速访问当前的应用程序状态,因此您可以重新访问该状态并使用向前和向后button在状态之间移动。
通过Flux,我们希望所有的操作都能通过调度程序,我想也包括URL更改。 您将如何pipe理stream量应用程序中的URL更改?
[更新]
在研究了一堆React / flux应用程序之后,我得出结论,我更愿意将路由分开处理,并正交于flux。 策略是URL /路由应该确定哪些组件被装载,并且组件根据需要根据路由参数和其他应用状态从商店请求数据。
[原始回答]
在用Flux进行实验的时候,我用最近的一个项目做了一个方法,就是把路由层设置成另一个存储。 这意味着更改URL的所有链接实际上都会通过调度程序触发一个操作,请求更新路由。 RouteStore
通过在浏览器中设置URL并设置一些内部数据(通过路由识别器 )来响应这个调度,以便视图可以在从存储中触发change
事件时查询新的路由数据。
对我来说,一个非显而易见的部分是如何确保URL更改触发操作; 我最终创build了一个mixin为我pipe理这个(注意:这不是100%强健的,但为我正在使用的应用程序工作;您可能需要进行修改,以满足您的需求)。
// 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); } } };
它会被这样使用:
var ApplicationView = React.createClass({ mixins: [RoutingMixin], handleRouteChange: function(newUrl, fromHistory) { this.dispatcher.dispatch(RouteActions.changeUrl(newUrl, fromHistory)); }, // ... });
商店中的处理程序可能如下所示:
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"); } }
野外的大多数例子都使用React Router ,这是一个基于Ember路由器的框架。 重要的部分是作为组件的声明式规范的路由configuration:
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)