superwf / vuex-cache

cache vuex action when dispatch
MIT License
510 stars 32 forks source link

'Dispatch' undefined when inside new Nuxt fetch() #47

Open nathanchase opened 4 years ago

nathanchase commented 4 years ago

In Nuxt 2.12+, there's a new fetch() method.

Example:

<script>
export default {
  async fetch() {
    await this.$store.cache.dispatch('getUser');
  },
};
</script>

Results in:

 ERROR  Error in fetch(): Cannot read property 'dispatch' of undefined

at VueComponent.fetch (server.js:6668:29)
at VueComponent.serverPrefetch (server.js:2515:31)
at waitForServerPrefetch (node_modules/vue-server-renderer/build.dev.js:8276:34)
at renderComponentInner (node_modules/vue-server-renderer/build.dev.js:8426:3)
at renderComponent (node_modules/vue-server-renderer/build.dev.js:8383:5)
at RenderContext.renderNode (node_modules/vue-server-renderer/build.dev.js:8294:5)
at RenderContext.next (node_modules/vue-server-renderer/build.dev.js:2598:23)
at cachedWrite (node_modules/vue-server-renderer/build.dev.js:2451:9)
at renderElement (node_modules/vue-server-renderer/build.dev.js:8544:5)
at renderNode (node_modules/vue-server-renderer/build.dev.js:8296:5)

My vuex-cache.js in ~/plugins:

import createVuexCache from 'vuex-cache';

export default ({ store, isHMR }) => {
  if (process.browser) {
    if (isHMR) {
      return;
    }

    const options = {
      timeout: 2 * 60 * 60 * 1000, // Equal to 2 hours in milliseconds.
    };

    const setupVuexCache = createVuexCache(options);
    window.onNuxtReady(() => setupVuexCache(store));
  }
};

I assume it's just because it is attempting to dispatch server-side but vuex-cache hasn't attached itself yet correctly to the $store instance.

Not sure if there's a solution to ensure that all dispatches server-side bypass the cache, and all client-side navigations include the cache action - barring doing twice the dispatch calls wrapped within if (process.browser) { checks?

VitorLuizC commented 4 years ago

I assume it's just because it is attempting to dispatch server-side but vuex-cache hasn't attached itself yet correctly to the $store instance.

This happens if you declare the plugin like in README.md. That configuration only allow vuex-cache to work client-side.

module.exports = {
  ...,
  plugins: [
    ...,
    { src: '~/plugins/vuex-cache.js', ssr: false },
  ]
};

Not sure if there's a solution to ensure that all dispatches server-side bypass the cache, and all client-side navigations include the cache action - barring doing twice the dispatch calls wrapped within if (process.browser) { checks?

process.browser is probably the best choice. Since vuex-cache uses a simple Map as store for your actions and I don't think there's a way to use it on both client and server.

if (process.browser)
  await this.$store.cache.dispatch('getUser');
else
  await this.$store.dispatch('getUser');
nathanchase commented 4 years ago

process.browser is probably the best choice. Since vuex-cache uses a simple Map as store for your actions and I don't think there's a way to use it on both client and server.

if (process.browser)
  await this.$store.cache.dispatch('getUser');
else
  await this.$store.dispatch('getUser');

Perhaps then there would be an opportunity to add a hook inside vuex-cache to check for typeof window === "undefined" and bypass itself allowing the dispatch to pass through directly - rather than force the user to define the check for every dispatch?

VitorLuizC commented 4 years ago

Perhaps then there would be an opportunity to add a hook inside vuex-cache to check for typeof window === "undefined" and bypass itself allowing the dispatch to pass through directly - rather than force the user to define the check for every dispatch?

I don't think so, vuex-cache can be executed without window because just depends on Vuex, Promise and Map. You can change declaration of the plugin in nuxt.config to allow vuex-cache in SSR too. It may fix the problem.

module.exports = {
  ...,
  plugins: [
    ...,
    '~/plugins/vuex-cache.js', // instead of { src: '~/plugins/vuex-cache.js', ssr: false }
  ]
};
wokalek-work commented 2 years ago

It's not fixing problem, it turns out just an empty store