3

How is a Flux based system meant to handle an uninitialized store.

For a variety of reasons, it makes sense to only initialize a store when that data is first requested. If I'm designing a Facebook Profile, I don't need to load the list of "friends" until the user clicks on the "friends" tab.

But if we have already loaded that data into a store, perhaps due to a different react component that needed the data previously, we don't want to send off unnecessary calls to the ActionCreator / API-util (thus taxing the server unnecessarily and undoing the benefit of reactjs quick rendering by waiting on ajax calls all the time).

I've come up with a couple of solutions, but none seem quite perfect.


  1. When a component needs data, it makes a call to the Get method of the store. If it receives no information back (empty object, or undefined), it fires an action to retrieve that data.

PROS: Seemingly within Flux architecture, our ActionCreator is only invoked by React Components. Good separation of concerns.

CONS: An absolutely insane amount of duplicate code. Every time a component wants to call "UsersStore.getFriends()" (or any other store get method), it must follow it with a check on the return value and an ActionCreator call if empty. That's a lot of boilerplate for something we're going to be using constantly.


  1. When a component needs data, it makes a call to the Get method of the store. Within this get method, the Store itself verifies if the response is empty. If it is, the Store itself triggers an action to retrieve the data.

PROS: Very streamlined. Every time we request information, we are sure to receive it (even if it means waiting for the next dispatch) without needing any repetitive code in the components.

CONS: This seems like a bend (or a break?) of the Flux structure. We're connecting our ActionCreator and our Stores directly.


  1. Within the componentDidMount and/or componentWillReceiveProps hooks of each component, include a call to ActionCreator to initialize any store that will be needed for this component.

PROS: Within Flux design of having actions sent only by components.

CONS: Outside of Flux design around Single Responsibility; We're now overtly burdening the components with the task of managing the initialization of the stores.


Are any of these valid design patterns for use with initializing flux stores? Is there a 4th better option that I missed?

Help!

Jake Haller-Roby
  • 6,335
  • 1
  • 18
  • 31

1 Answers1

1

Facebook internally have used your option 2 at least once - see https://news.ycombinator.com/item?id=7721292

In my large client app, we use option 1. However, there isn't any code duplication. Most getter functions return a 'MaybeData' instance, which includes a 'data' field containing the data, a placeholder for it, or the partial data that is currently available. It also includes a 'dataQueries' field that contains the list of 'queries' required to make 'data' complete, if any. The generic flux wrapper React component then dispatches an action for any queries it has got back. (The generic flux wrapper component maps store state to React component state, and then passes it to the wrapped component as props, like Facebook Flux's Container (https://facebook.github.io/flux/docs/flux-utils.html#content))

The store state getters are always pure functions with no side effects (and are often memo-ized based on the parts of store state they actually access, for performance - somewhat similar to the 'reselect' library: https://github.com/reactjs/reselect).

So option 2 might be simpler and a good fit if you are programming in a more imperative/OO-style flux approach. Option 1 might be a better fit if you have a more functional 'redux' style approach (https://github.com/reactjs/redux).

TomW
  • 3,923
  • 1
  • 23
  • 26
  • Great information, thank you! I think the part I was obviously overlooking was the wrapper/container component that is tasked with managing and disseminating data. Having this single point of contact reduces the duplicate-code concern entirely, in much the same way that the Dispatcher removes the need to make multiple data queries to populate different stores. – Jake Haller-Roby Feb 17 '16 at 17:40