2014-05-13 7 views
41

jako uzupełnienie do Store lifecycle question,W architekturze Flux, w jaki sposób zarządzać stacjami routingu/adresami URL po stronie klienta?

W typowej aplikacji internetowej dobrze jest mieć skrót do aktualnego stanu aplikacji za pośrednictwem adresu URL, dzięki czemu można ponownie odwiedzić ten stan i korzystać z przodu iz tyłu przycisków do poruszania między państwami.

Z Flux chcemy, aby wszystkie akcje przechodziły przez program rozsyłający, co, jak sądzę, obejmuje również zmianę adresu URL. jak zarządzałbyś zmianami adresów URL w aplikacji strumienia?

+0

mógłbyś wyjaśnić co masz na myśli, przechodząc między stanami w swoje pytanie? Myślę, że nie masz na myśli stanu aplikacji, ale raczej poruszania się między adresami URL tras/SPA. Jeśli tak, Flux jest jedynie architekturą aplikacji, która opisuje komunikację między aplikacjami i kontrolę. Społeczność Flux ogólnie zdecydowała, że ​​routing jest poza zakresem i zobacz odpowiedź Nacho na re: router reagowania. –

Odpowiedz

43

[Aktualizacja]

Po pracy na pęczek React/aplikacji topnika, doszedłem do wniosku, że wolę routingu być traktowane oddzielnie i prostopadle do topnika. Strategia polega na tym, że adresy URL/trasy powinny określać, które komponenty są montowane, a komponenty żądają danych ze sklepów na podstawie parametrów trasy i, w razie potrzeby, innego stanu aplikacji.

[Original Odpowiedź]

Podejście wziąłem z ostatnim projekcie podczas eksperymentowania z Flux było wykonanie warstwy routingu tylko kolejny sklep. Oznacza to, że wszystkie linki, które zmieniają adres URL, faktycznie wywołują akcję za pośrednictwem kontrolera żądającego uaktualnienia trasy. Odpowiedź na tę wiadomość została przesłana na adres RouteStore, ustawiając adres URL w przeglądarce i ustawiając niektóre dane wewnętrzne (przez route-recognizer), aby widoki mogły wysyłać zapytania do nowych danych routingu po zdarzeniu ze sklepu ze zdarzenia change.

Jednym z nieoczywistych elementów dla mnie było to, jak zapewnić, że zmiany URL wywołały akcje; Skończyło się na tym, że utworzyłem mixin, aby to sobie poradzić (uwaga: to nie jest w 100% niezawodne, ale działało dla aplikacji, z której korzystałem, być może będziesz musiał wprowadzić modyfikacje dostosowane do twoich potrzeb).

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

Byłoby być używany jako tak:

var ApplicationView = React.createClass({ 
    mixins: [RoutingMixin], 

    handleRouteChange: function(newUrl, fromHistory) { 
    this.dispatcher.dispatch(RouteActions.changeUrl(newUrl, fromHistory)); 
    }, 

    // ... 
}); 

procedury obsługi w sklepie może wyglądać:

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"); 
    } 
} 
+2

Co powiesz na zintegrowanie routingu z dyspozytorem? Niektóre wydarzenia zostaną przekształcone w trasę. Następnie, gdy ktoś trafi na trasę, dyspozytor może wysłać wydarzenie związane z tym. –

+0

@BinaryMuse, z jakiego powodu podszedłeś do zaktualizowanego wniosku? Zarządzam większą aplikacją Angular, która jest dość reaktywna i zwracam się do FLUX wyłącznie w celu uzyskania pojedynczego przepływu danych. Ciekawe, dlaczego wolisz inne rozwiązanie routingu, ponieważ właśnie zaczynam. –

+0

@BryanRayner Strumienie Flux zasadniczo biorą zdarzenia (akcje) i redukują je do zmian stanu, które są przechowywane w sklepach. Routing jest w zasadzie już taki: zdarzenia historii przeglądarki są czynnością, a sklep jest bieżącym adresem URL. Odkryłem, że dodanie tutaj dodatkowej złożoności nie przynosi żadnych korzyści. Dodatkowo, ze wszystkimi możliwymi do przekształcenia stanami w adresie URL, jest jasne, co jest zapisane, a co nie. –

2

większość przykładów w dzikiej wykorzystują React Router, ram w oparciu o router Ember. Ważną częścią jest konfiguracja tras jak deklaratywnej specyfikacji komponentów:

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)