0

I am using react with flux architecture and I have a problem I face it.
I need to create an action that gets a user id and fetches the user. Here is the code:

var createAction = require('common/scripts/actions-helpers/create-action'),
    resource = require('common/scripts/resources/conversation');

module.exports = createAction(fetchAction);

function fetchAction(context, payload, success, failure) {
    resource.sync(context, payload.userId)
        .then(function(user) {
            context.dispatch('USER_FETCH', user);
            success();
        }, failure);
}

I want to use a store that will cache all users so in case the user fetched before, the action will not perform a backend call. The new action should look like that:

function getFetchedUser() {
    // <--------- HOW TO KNOW WHETHER USER FETCHED?
}

function fetchAction(context, payload, success, failure) {
    var user = getFetchedUser();
    if (user) {
        context.dispatch('USER_FETCH', user);
        success();
    } else {
        resource.sync(context, payload.userId)
            .then(function(user) {
                context.dispatch('USER_FETCH', user);
                success();
            }, failure);
    }
}

The issue is that I don't want to manage users data in the action so the only way come in my mind to implement getFetchedUser() is checking in the Users store.
Is this a good approach?
Can action access to store?

Naor
  • 23,465
  • 48
  • 152
  • 268

2 Answers2

0

The common approach is to do the backend call from the action and then dispatch an action when the request either succeeds or fails. This way you can populate your store with an action. This means that the store keeps synchronous and can just emit changes as they come along.

var AppDispatcher = require(<Flux AppDispatcher>);
var UserActions = {

  fetchUser: function(payload) {
     fetchUserFromBackendApi(payload)
     .then(function (error, user) {
        if(error) {
           AppDispatcher.dispatch({
              actionType: "ERROR_CODE",
              error: error
          });
          return;
        }
       AppDispatcher.dispatch({
          actionType: "SUCCESSFUL_USER",
          user: user
       });
     }
  }
};

module.exports = UserActions;

Then you just handle different action types in the store and just populate your cache. When the cache is populated you emit a change event and the data will be rendered in.

This code ain't the prettiest so howl out if I misunderstood or if there are any questions.

So to answer the intial answer. The action component should not talk to the store. It goes against one of the key concepts of React, loose coupling. With Flux and React the data flow works out because the components will fire actions when they need data. The actions just fetch the data.

magnudae
  • 1,272
  • 2
  • 13
  • 32
  • This doesn't really answer the question since it will make the backend call even if the data already exists in the store or not. – Markus-ipse Mar 12 '15 at 19:35
  • Is there a need to check if a user i fetched twice? If you fetch the user, you can emit the change and send the user data to the component which needs it. Is the data in need of updating often? You should not make the action talk directly to the store. This loose coupling is one of the key concept of React. It is often the components state and props which decide if they got the proper data, and then fire actions to collect them. – magnudae Mar 12 '15 at 19:53
  • Oh didn't see that you weren't the asker. You can disregard the first question in my comment. – magnudae Mar 12 '15 at 20:02
  • @magnudae Thanks for your answer, but it doesn't answer my question. I know exactly what is the classical use case with flux actions and stores, but how can I prevent backend call in case I already have the data. I asked whether action can use a store on not. – Naor Mar 13 '15 at 22:31
  • I am not sure I understand, but your store could communicate with another store. So in your case, your store receives the action, asks the user store if it has the user. If yes, return the user, else do the backend call. Or I am not sure I understand your question. – Jeremy D Mar 14 '15 at 19:22
  • I apologize for misunderstanding. You are free to do whatever you please do do with the store and action, but it seems to me that if an action gets dependent of a store it does not fit with the Flux data flow. I have not encountered that scenario, so this is purely for the discussion. Anyway, I would reconsider my data flow anyway if I encountered this scenario. It sounds more like a bad architectural problem, more than a Flux problem. – magnudae Mar 16 '15 at 07:34
  • 1
    I'm not understanding how it is a bad architectural problem to cache data? Flux isn't perfect and Facebook's Relay is addressing some of the issues with Flux and basically acknowledging Flux will be a front-end pattern going forward. It's a shortcoming of the one-way flow in Flux. If your store already has the desired data why ask a remote service for that data again? – mgutz Apr 01 '15 at 02:21
0

I also had a similar problem. I have a PhotosStore that keep all photos from a user, server send it paginated.

User can reorder photos by more recently, more commented, more viewed. Is PhotosStore has all page loaded, it can reorder by itself, if not, need call server.

# actions
Actions.Photo = createActions(
  'sortBy', {'load': asyncResult: true}
)

# store
Store.Photos = Reflux.createStore(
  listenables: Actions.Photo

  onSortBy: (order) ->
    if @hasMorePages()
      Actions.Photo.load({order: order})
    else 
      # reorder and trigger

  onLoadCompleted: (data) ->
    # get data and trigger
)

# view
PhotoHeaderOrder = React.createClass
  mixins: [
    Reflux.connect(Store.Photos, 'model')
  ]

  onSortNew: -> Actions.Photo.sortBy('news')
  onSortCom: -> Actions.Photo.sortBy('comments')
  onSortVie: -> Actions.Photo.sortBy('views')

  render: ->
    # render code
  • In case I understood your code, do you trigger an action from your store? Is this good approach or a hack? – Naor Apr 01 '15 at 22:49