ActionBlockers

If you've been copying the source code in the previous pages you may have thought "wait, isn't this going to hit the Github API unneccesarily even when I already have the data locally?"

The answer to that is at the moment, yes. In src/HomeContainer.js you'll see this:

  methods: {
    search: dispatch => query => {
      return dispatch(getUserSearch({ query }));
    },
  },

This means whenever search is called by the aesthetic component, the action will be fired and the API called. This is useful in some situations but it's not what we want in others. For instance, we don't want to repeat the same call here if we've already searched for a query and it returned something.

Any Gambit action created using createStagedAction accepts a second parameter of a function. If this function evaluates to false, this will prevent the actionCreator from firing _START, _DONE, _FAILED and calling the API.

The function will be provided with a timestamp of the last time an ActionCreator with the same ID (see Actions for how to change an Actions ID) was called.

Remember our getUserSearch ActionCreator was written like this:

export const getUserSearch = createStagedAction(
  UserConstants.GET_USER_SEARCH,
  api => api.user.search,
  {
    id: (constant, { query }) => `${constant}_${query}`,
  },
);

So the id of the ActionCreator changes depending on the query. All we have to then is change the method invocation to:

  methods: {
    search: dispatch => query => {
      return dispatch(getUserSearch({ query }, () => false));
    },
  },

And it won't fire getUserSearch actions when the action has been fired with the same query. Conventionally we use one of Gambit's built in ActionBlockers to do this:

import { hasNotBeenCalled } from 'gambit';

...
  methods: {
    search: dispatch => query => {
      return dispatch(getUserSearch({ query }, hasNotBeenCalled));
    },
  },
...

There is also another built in ActionBlocker called hasNotBeenCalledIn that has the following signature:

hasNotBeenCalledIn(integer, unit)

e.g.
return dispatch(getUserSearch({ query }, hasNotBeenCalledIn(5, 'mins')));

This is useful for when data can become stale.

Making ActionBlockers work

In order to use any ActionBlockers, you'll need to make sure you include the gambitReducer in your appReducer. We'll show you what that looks like on the next page.