0

I curious if there is any agreed upon pattern to check if data has been already loaded before hitting the server.

Say I have my action that looks like this:

Actions.loadRequest.preEmit = function () {
  $.get('/store/', function (data) {
      Actions.loadSuccess(data);
  }.bind(this));
}

This is called from a component that is simply saying give me this data: But I don't want to hit the server if that data is already in the store. Should I store the logic of checking the store in the component:

render: function () {
  var data = this.state.store.data;
  if (!data) {
    Actions.loadRequest();
  }

Is there a better way to go about this?

Dan Baker
  • 1,757
  • 3
  • 21
  • 36
  • I added cacheing to my actual API utils file. So anywhere in the app that requests an API, the method itself will check if the data has been cached, and if so resolve the promise with that instead of a HTTP request. Whenever you receive an HTTP response, though, you would have to add it to the cache. – BradByte Aug 11 '15 at 14:47
  • This an interesting approach. Do you know of any resources that demo an implementation of this? – Dan Baker Aug 11 '15 at 15:04
  • It's not using a flux model, but this example was helpful in my implementation... https://github.com/rackt/react-router-mega-demo. – BradByte Aug 11 '15 at 18:55
  • Check out the /utils/api.js and /utils/cache.js. It's primarily an example for isomorphic server side data loading, but might provide some ideas. – BradByte Aug 11 '15 at 18:56

1 Answers1

1

In my project I use shouldEmit for this (see https://github.com/reflux/refluxjs#action-hooks). An example from my code:

var streamStore = Reflux.createStore({
    [...]
});

actions.loadStream.shouldEmit = function(streamId) {
    if(streamId in streamStore.data)
        return false;
    return true;
};

This lives in the same file as the store definition. I think this is conceptually the right approach because the store saves the data, so the store should be responsible for intercepting the request to load more data and saying not to, just as it's responsible for listening to the action saying more data is available and updating itself.

Unfortunately this won't work with your example because you bound the AJAX call to preEmit, which gets called before shouldEmit. I would suggest refactoring to make the API call in a normal listen call, like this:

Actions.loadRequest.listen(function () {
  $.get('/store/', function (data) {
      Actions.loadSuccess(data);
  }.bind(this));
});

This saves preEmit for the rare case of needing to rewrite an action's arguments before emitting it. I do use this pattern in my code, for example when loading a second page of results, which relies on a next token that came with the first page and is thus in the store. But in the general simple case of "action triggered, so make a request", using listen makes more sense because then you can add preEmit and shouldEmit for more advanced behavior, like the caching you want.

Reflux also has a helper function, listenAndPromise, which further simplifies the common use case of "action fired, make AJAX call, then fire another action when it's done". Your example could become:

Actions.loadRequest.listenAndPromise(function () {
    return $.get('/store/');
});    

See this section of the docs for more info on how to set that up: https://github.com/reflux/refluxjs#asynchronous-actions

user686782
  • 992
  • 1
  • 10
  • 18
  • just to clarify: 1. your actions live in the same file as your store so that you can reference your store in `shouldEmit` 2. instead of wrapping `loadSuccess` in `preEmit` i should wrap in a different action. 3. i could use `listenAndPromise` which would need to return a promise that would then know to call `loadSuccess` or `loadFail` how? – Dan Baker Aug 12 '15 at 18:53
  • 1. No, the store file contains `shouldEmit` and the store, and imports action from the actions file (which it was already doing to listen to them). 2. You can simply use `listen` on the same action, instead of `preEmit`. The order of calls for each action is `preEmit` -> `shouldEmit` -> `listen`. 3. Reflux will automatically bind to the `then` and `catch` of the promise and call the `completed` and `failed` sub-actions. The docs I linked explain more. Don't worry too much about this part; it's not critical to your original question. – user686782 Aug 12 '15 at 19:03