如何在Flux中加载初始数据,但仅限于组件需要它

时间:2015-10-13 22:59:46

标签: reactjs reactjs-flux

我试图尽可能地坚持Flux模式,但我必须遗漏一些东西,因为我无法想象如何在不使用hack或做出错误的模式的情况下让它工作。

我有一个由大量数据分段的应用程序。让我们说它是一个资源管理应用程序,公司的每个部门都有不同的资源集。该应用程序的用户将始终访问他们所属的任何部门,并留在那里。有些人可能有他们管理的多个部门。

因此,在此应用程序的顶部,将有一种方法可以选择您正在使用的部门。

这里的关键是,在部门列表加载之前,我无法显示任何有用的内容,而且我已选择要显示的部门(目前只是列表中的第一项)。

要实现此目的,应用程序的根组件会查看DepartmentStore以确定它当前是否正在加载。如果它正在加载,它甚至不会打扰渲染组件。像这样:

    function initApp(projectSlug) {
        // prefetch some data!
        DeptActions.getAll();
    }

    function getStateFromStores() {
        return {
            loading: DeptStore.getLoading()
        };
    }

    export default React.createClass({
        getInitialState: function() {
            return getStateFromStores();
        },
        componentDidMount: function() {
            initApp();
            DeptStore.addChangeListener(this._deptChange);
        },
        componentWillUnmount: function() {
            DeptStore.removeChangeListener(this._deptChange);
        },
        _deptChange: function() {
            this.setState(getStateFromStores());
        },
        render: function() {
            return (
                this.state.projectsLoading
                    ? <div>Loading...</div>
                    : (<div>
                        <Header/>
                        <div className="body-content">
                            <div className="grid-container">
                            {this.props.children}
                            </div>
                        </div>
                      <Footer/>
                      </div>)
                );
        }
    });

props.children将是React Router指定的任何组件。

这样,页面的实际组件可以呈现并理所当然地认为所有部门都已加载,并且已经设置了“当前”部门。

问题是组件一旦呈现,就需要开始加载部门的资源。为了开始这个过程,它会在安装时启动一个动作:

componentDidMount: function(){
    ResourceActions.getResources();
},

此操作将启动一个API调用,该调用使用DeptStore的当前部门来了解要加载的内容。然后它调度一个RESOURCE_LOADING事件,也许你可以猜测,它失败了,因为:

Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.

这是因为基本上,部门加载的操作会导致资源组件呈现,这会尝试启动资源获取操作。一个动作导致另一个动作。

关于此类问题的所有示例和类似问题对我来说都不尽如人意。例如:

Flux Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch

a scenario flux doesn't support

即使是来自Facebook的Todo列表和Chat App示例也没有解决这个问题。 Todo列表甚至没有加载的“初始”数据。聊天应用程序可以,但它只是在应用程序启动时加载所有消息。

我无法在应用启动时加载资源,因为我必须首先知道哪个部门。即使我以某种方式知道这一点,我也不想加载资源,除非资源组件需要它们。用户可能在当前部门的其他页面上,而不显示资源。因此,以某种方式加载资源以响应原始的Dept更改事件对我来说也不可行。

请帮助我获得解决此问题的缺点? :)我如何将Departments列表分开,然后加载Resources以响应Departments的加载,并执行它以便它以某种方式由组件驱动,这样我就不会进行昂贵的Resources API调用,除非页面上的组件需要吗?

1 个答案:

答案 0 :(得分:2)

正如其他帖子中的答案所指出的,这是助焊剂模式解决方案中的一个缺点/漏洞。唯一的解决方法(类似于之前的答案)是从顶部组件中的componentDidMount()componentDidUpdate()创建一个调用,其执行类似的操作:

checkAndFetchResources: function() {
  if (this.props.resourcesToRender != undefined) {
    ResourceActions.getResources();
  }
}

将作为props获取的资源传递给资源组件。 这样,在上一轮调度之后调用您的获取操作,然后渲染周期完全结束。

这与之前提供的答案类似,因此可能不适合您(正如您在问题中所述)。在这种情况下,进一步澄清为什么答案不符合您的需求会有所帮助。