3

I am trying to adhere to the Flux pattern as best I can, but I must be missing something, because I can't figure how to get this to work without using a hack or doing something that feels wrong for the pattern.

I have an application that is segmented by big buckets of data. Let's say its a Resource Management app, and each Department in the company has a different set of resources. Users of the app will always go to whatever department they are a member of, and stay there. Some people may have multiple departments they manage.

So, at the top of this app there will be a way to select what Department you are working with.

The key here is that I cannot really display anything useful until the list of departments has loaded and I have selected which department to display (which will just be the first item in the list for now).

To accomplish this, the root component of the app looks at the DepartmentStore to determine if it is currently loading or not. If it is loading, it does not even bother rendering the component. Something like this:

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

The props.children will be whatever component was designated by React Router.

This way, the actual component for the page can render and take for granted that all the departments are loaded and there is a "current" department already all set up.

The problem is that the component, once it renders, needs to start loading the resources for the department. In order to begin that process, it kicks off an action when it mounts:

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

This action will kick off an API call that uses the DeptStore's current Department to know what to load. Then it dispatches a RESOURCE_LOADING event, and, perhaps you can guess, it fails, because:

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

That's because basically, the action of the departments loading causes the resource component to render, which tries to kick off a resource fetch action. One action leads to another.

All the examples and similar questions about this type of issue aren't satisfactory to me. For example:

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

a scenario flux doesn't support

Even the Todo list and Chat App examples from Facebook do not address this. The Todo list doesn't even have 'initial' data that loads. The Chat App does, but it simply loads all the messages when the app starts.

I cannot load the Resources when the app starts, because I have to know for which department first. Even if I somehow knew that, I do not want to load the Resources unless the Resources component needs them. The user may be on other pages with the current Department, which do not display the Resources. So somehow loading the Resources in response to the original Dept change event is not viable to me either.

Please help me get the insight I'm missing to solve this problem? :) How do I keep the list of Departments separate, and then load Resources in response to the Departments loading, and do it so that it is somehow driven by the component, so that I don't make an expensive Resources API call unless the component on the page needs it?

Community
  • 1
  • 1
InfinitiesLoop
  • 14,349
  • 3
  • 31
  • 34

1 Answers1

2

As the answers in the other posts point out, this is a shortcoming/ hole in the flux pattern solution. The only workaround (similar to previous answers), is to create a call from componentDidMount() and from componentDidUpdate() in the top component, which does something like:

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

And pass the resources fetched as props to the resources component. That way, your fetch action is called after the previous dispatch round followed by render cycle is completely finished.

This is similar to previously provided answers, so may not be sufficient for you (as you state in your question). In that case, further clarification on WHY the answers do not meet your needs would help.

wintvelt
  • 13,855
  • 3
  • 38
  • 43