markdalgleish / redial

Universal data fetching and route lifecycle management for React etc.
1.1k stars 42 forks source link

Defer fetching done 2 times #20

Closed andresgutgon closed 8 years ago

andresgutgon commented 8 years ago

Hi I've migrated a project to redial. It's looking great. The API is very clear and implementation is easy. All is working great for now. The only issue is that I have a deferred request that is done 2 times. This is the code:

@provideHooks({
  defer: (options) => {
    const {
      store: { dispatch },
      params: { id },
    } = options;

    return dispatch(loadInvitations(id));
  }
})

The method loadInvitations is a redux action that it's a Promise.

This is the commit where I'm trying to implement redial: https://github.com/coopdevs/katuma-web/pull/9/files

Any clue why the fetch is done 2 times?

andresgutgon commented 8 years ago

I can manage to do defer request only once if i throttleit:

import _ from 'underscore';

const callProvidedHooks = _.throttle((location, callback) => {
  // Match routes based on location object:
  match({ routes, location }, (routerError, redirectLocation, renderProps) => {
    if (redirectLocation) return;

    // Get array of route components:
    const components = renderProps.routes.map(route => route.component);

    const locals = {    };

    // Don't fetch data for initial route, server has already done the work:
    const invoke = window._data ? Promise.resolve.bind(Promise) : trigger;

    invoke('fetch', components, locals) // Fetch mandatory data dependencies for 2nd route change onwards
      .then(() => trigger('defer', components, locals)) // Fetch deferred, client-only data dependencies
      .then(() => trigger('done', components, locals)) // Finally, trigger 'done' lifecycle hooks
      .then(callback);
  });
}, 500); // <---- HERE IS THE HACK!

  // Handle initial rendering
history.listen((location) => {
  if (window.__data) {
    // Delete global data so that subsequent data fetches can occur:
    callProvidedHooks(location, () => delete window.__data);
  }
});

history.listenBefore(callProvidedHooks);
andresgutgon commented 8 years ago

But it's not a solution. Only is to see that there are arriving multiple events to history.listen and history.listenBefore

markdalgleish commented 8 years ago

In your code snippet, you're attaching trigger to both history.listen and history.listenBefore, which means that every route change will result in all hooks being run twice. In the app I'm working on, we only use history.listen. Could you explain to me why you're using both?