【问题标题】:In Flux architecture, how do you manage client side routing / url states?在 Flux 架构中,如何管理客户端路由/url 状态?
【发布时间】:2014-06-30 17:42:08
【问题描述】:

作为Store lifecycle question 的后续行动,

在典型的网络应用程序中,通过 URL 有一个指向当前应用程序状态的快捷方式非常好,这样您就可以重新访问该状态并使用前进和后退按钮在状态之间移动。

使用 Flux,我们希望所有操作都通过调度程序,我猜这还包括 URL 更改。您将如何管理通量应用程序中的 URL 更改?

【问题讨论】:

  • 您能否澄清在您的问题中导航的意思是什么?我认为您不是指应用程序状态,而是在路由/SPA url 之间导航。如果是这样,Flux 只是一个描述应用程序间通信和控制的应用程序架构。 Flux 社区通常认为路由超出了范围,请参阅 Nacho 的回答:react router。

标签: reactjs reactjs-flux


【解决方案1】:

大多数示例都使用React Router,这是一个基于 Ember 路由器的框架。重要的部分是将路由配置为组件的声明式规范:

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)

【讨论】:

    【解决方案2】:

    [更新]

    在处理了一堆 React/flux 应用程序之后,我得出的结论是,我更喜欢将路由单独处理并与 Flux 正交。策略是 URL/路由应该确定哪些组件被挂载,组件根据路由参数和其他应用程序状态从存储请求数据。

    [原答案]

    我在最近的一个项目中尝试使用 Flux 时采用的一种方法是让路由层成为另一个商店。这意味着所有更改 URL 的链接实际上都会通过调度程序触发一个动作,请求更新路由。 RouteStore 通过在浏览器中设置 URL 并设置一些内部数据(通过 route-recognizer)来响应此调度,以便视图可以在商店触发 change 事件时查询新的路由数据。

    对我来说,一个不明显的部分是如何确保 URL 更改触发操作;我最终创建了一个 mixin 来为我管理它(注意:这不是 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");
      }
    }
    

    【讨论】:

    • 如何将路由集成到它自己的调度程序中?一些事件将被转换为路线。然后当有人命中路由时,调度员可以调度与此相关的事件。
    • @BinaryMuse,您得出最新结论的原因是什么?我正在管理一个较大的 Angular 应用程序,该应用程序具有相当的反应性,并且转向 FLUX 纯粹是为了尝试获得单一的数据流。知道为什么您更喜欢不同的路由解决方案会很有趣,因为我刚刚开始。
    • @BryanRayner Flux 存储本质上是接受事件(动作)并将它们减少为存储在存储中的状态变化。路由基本上是这样的:浏览器历史事件是动作,商店是当前 URL。我发现在这里增加额外的复杂性似乎并没有带来任何好处。此外,通过 URL 中的所有可序列化状态,可以清楚地知道哪些保存在那里,哪些没有保存。
    • 确实如此。我们正在构建一个 Angular 应用程序,其中只有一部分代码库使用 FLUX 风格的架构。就像您在更新的答案中所写的那样,我得出的结论是,路由器应该继续正常加载控制器、模板等,然后这些组件根据反序列化的 URL 参数调用必要的操作。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 2021-07-03
    • 1970-01-01
    • 2018-10-15
    • 2014-06-28
    • 2015-06-23
    • 2017-10-30
    相关资源
    最近更新 更多