【问题标题】:Flux / Fluxible: Updating routes based on state changeFlux / Fluxible:根据状态变化更新路由
【发布时间】:2025-12-18 11:00:02
【问题描述】:

使用 Fluxible 和 react 路由器根据状态存储的更改触发路由更改的最简洁方法是什么?

一个示例组件可能会接受一些用户输入并在点击事件上调用一个动作(为简洁起见)

class NameInput extends React.Component {

    constructor (props) {
        super(props);
        this.state = props.state;
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick (event) {
        this.context.executeAction(setName, {name:'Some User Value'});
    }

    render () {
        return (
            <div>
                <input type="button" value="Set Name" onClick={this.handleClick} />
            </div>
        );
    }
}

export default Home;

handleClick 方法执行一个 Action,它可以用我们的新值更新 Store。

但是如果我希望它在商店更新后触发导航怎么办?我可以添加router上下文类型,执行Action后直接调用transition方法:

this.context.executeAction(setName, {name:'Some User Value'});
this.context.router.transitionTo('some-route');

但这假设setName Action 是同步的。假设一旦 Action 完成并且 Store 更新后新路由将​​重新渲染,这在概念上是否安全?

或者,原始组件是否应该监听 Store Changes 并根据对 store 状态的一些评估来启动路由转换?

使用 Fluxible,connectToStores 实现,我可以监听 Store 状态的谨慎变化:

NameInput = connectToStores(NameInput, [SomeStore], function (stores, props) {
    return {
        name: stores.SomeStore.getState().name
    }
});

如何使用这种类型的 Store 监听器来启动路由更改?

【问题讨论】:

    标签: javascript reactjs reactjs-flux react-router


    【解决方案1】:

    最好的方法是按照@ambroos 的建议创建一个新动作, setNameAndNavigate。不过,对于导航,请使用 navigateAction https://github.com/yahoo/fluxible/blob/master/packages/fluxible-router/lib/navigateAction.js,您只需将 url 作为参数。 像这样的,

    import async from 'async';
    import setName from 'some/path/setName'; 
    
    export default function setNameAndNavigate(context, params, done) {
       async.waterfall([
          callback => {
              setName(context, params, callback);
          },
          (callback) => {
              navigate(context, {
                 url: '/someNewUrl',
              }, callback);
           }
       ], done);    
    }
    

    让你的行动尽可能地成为主要工作者。

    【讨论】:

      【解决方案2】:

      我在自己的应用程序中注意到,对于这些类型的流程,让操作完成所有繁重的工作通常更安全。烦人的是路由器无法通过操作访问。

      所以,这就是我要做的:

      创建一个同时执行这两个操作的元操作:setNameAndNavigate。作为有效载荷,您可以使用以下内容:

      {
         name: 'Value',
         destination: {to: 'some-route', params: []},
         router: this.context.router
      }
      

      然后,在您的操作中,在 setName 完成时进行导航。

      这并不理想,尤其是将Router传递给action。可能有一些方法可以将路由器附加到动作上下文,但这并不像我希望的那么简单。不过,这可能是一个很好的起点。


      补充阅读:

      为什么一切都在行动?在组件中执行操作以响应存储更改是有风险的。从 Fluxible 0.4 开始,您不能再让操作在 inside 另一个分派中分派。这发生的速度比您想象的要快得多,例如,执行一个操作以响应存储中的更改,而不用setImmediatesetTimeout 延迟它,将杀死您的应用程序,因为存储更改在调度期间同步发生。

      但是,在操作内部,您可以轻松地执行操作和调度,并等待它们完成后再执行下一个操作。

      以这种方式工作的最终结果是,您的大部分应用程序逻辑都转移到了操作中,并且您的组件变成了简单的视图,这些视图响应用户交互(点击/滚动/悬停/...,只要它不是响应商店更改)。

      【讨论】:

      • 谢谢,从动作内部启动导航是我最初计划的,但我认为路由器在 actionContext 上不可用一定是有原因的。只要操作保持无状态并且不保留它,在有效负载中传递它似乎就可以了。去玩这个,看看我想出了什么。谢谢。
      • 这是使用fluxibleContexts 的一个缺点。遵循 Flux 指南,路由器应该在组件中以只读方式使用,并且对路由器有影响的动作应该只能在动作中使用。导航是“状态变化”。如果没有 React-Router,这将是对 RouteStore/ApplicationStore 的更改。通过从组件内部执行此操作,您违反了 Flux。将路由器传递给操作是一种解决方法,但最终会“更好”。
      • 同意直接从组件调用它不是要走的路。看起来最好的答案可能是创建一个类似于 github.com/yahoo/fluxible-plugin-routr/blob/master/docs/… 但使用 react-router 的插件