Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Flux architecture, how do you manage client side routing / url states?

As a follow up to the Store lifecycle question,

In a typical web app its nice to have a shortcut to the current application state via the URL so you can re-visit that state and use the forward and back buttons to move between states.

With Flux we want all actions to go through the dispatcher, which i guess also include an URL change. how would you manage URL changes within a flux application?

like image 398
krs Avatar asked May 13 '14 07:05

krs


People also ask

What is Flux state management?

What is flux? Flux uses a unidirectional data flow pattern to solve state management complexity. Remember it is not a framework – rather it's more of a pattern that targets to solve the state management issue.

How does client-side routing work?

Client side routing is a type of routing where as the user navigates around the application or website no full page reloads take place, even when the page's URL changes. Instead, JavaScript is used to update the URL and fetch and display new content.

What is Flux Flux architecture in detail?

Flux is the application architecture that Facebook uses for building client-side web applications. It complements React's composable view components by utilizing a unidirectional data flow. It's more of a pattern rather than a formal framework, and you can start using Flux immediately without a lot of new code.

What is the data flow of Flux?

In Flux application, data flows in a single direction(unidirectional). This data flow is central to the flux pattern. The dispatcher, stores, and views are independent nodes with inputs and outputs. The actions are simple objects that contain new data and type property.


1 Answers

[Update]

After working on a bunch of React/flux applications, I've come to the conclusion that I prefer for routing to be handled separately and orthogonally to flux. The strategy is that the URL/routes should determine which components get mounted, and the components request data from the stores based on the route parameters and other application state as necessary.

[Original Answer]

An approach I took with a recent project while experimenting with Flux was to make the routing layer just another store. This means that all links that change the URL actually trigger an action through the dispatcher requesting that the route be updated. A RouteStore responded to this dispatch by setting the URL in the browser and setting some internal data (via route-recognizer) so that the views could query the new routing data upon the change event being fired from the store.

One non-obvious piece for me was how to ensure URL changes triggered actions; I ended up creating a mixin to manage this for me (note: this isn't 100% robust, but worked for the app I was using; you may have to make modifications to suit your needs).

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

It would be used as so:

var ApplicationView = React.createClass({   mixins: [RoutingMixin],    handleRouteChange: function(newUrl, fromHistory) {     this.dispatcher.dispatch(RouteActions.changeUrl(newUrl, fromHistory));   },    // ... }); 

The handler in the store might look something like:

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");   } } 
like image 166
Michelle Tilley Avatar answered Sep 20 '22 11:09

Michelle Tilley