Skip to content

Data pre-fetching about sub components #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
harvey-woo opened this issue May 22, 2017 · 9 comments
Closed

Data pre-fetching about sub components #29

harvey-woo opened this issue May 22, 2017 · 9 comments

Comments

@harvey-woo
Copy link

harvey-woo commented May 22, 2017

This document descibing data pre-fetching about the components whitch router.getMatchedComponents
But how about the sub components those belong the matched components,
how to load pre-fetching data with these components?

https://ssr.vuejs.org/en/data.html#

@egoist
Copy link

egoist commented May 22, 2017

Prefetching data in route components and pass them down as props to ( or use vuex in) child components.

@jazoom
Copy link

jazoom commented May 28, 2017

I wondered this myself a while ago. The answer was to make them child routes in the router and use <router-view></router-view> (can be named or not named) to insert the children where I wanted.

Maybe this should be mentioned in the documentation so others don't need to find out by experimentation as well?

kazupon added a commit that referenced this issue Jul 9, 2017
* Translate SUMMARY.md via GitLocalize

* Revert "Chinese Translation: zh/summary"

* Revert "Revert "Chinese Translation: zh/summary""

* Japanese Translation: ja/css.md (#19)

* Translate css.md via GitLocalize

* Translate css.md via GitLocalize

* Update css.md

Remove style closing tags

* Translate css.md via GitLocalize

* Update css.md

* Translate api.md via GitLocalize

* Translate streaming.md via GitLocalize (#22)

* Translate caching.md via GitLocalize (#23)

* Japanese Translation: ja/routing.md (#18)

* Translate routing.md via GitLocalize

* Translate routing.md via GitLocalize

* Translate universal.md via GitLocalize (#29)

* ja/api.md (#28)

* Translate api.md via GitLocalize

* Translate api.md via GitLocalize

* Translate api.md via GitLocalize

* Translate api.md via GitLocalize

* Translate build-config.md via GitLocalize (#27)

* Translate build-config.md via GitLocalize

* Translate build-config.md via GitLocalize

* Translate build-config.md via GitLocalize

* Japanese translation: bundle-renderer.md (#30)

* Translate bundle-renderer.md via GitLocalize

* Translate bundle-renderer.md via GitLocalize

* Translate basic.md (#32)

* Translate basic.md via GitLocalize

* Translate basic.md via GitLocalize

* Translate basic.md via GitLocalize

* Translate basic.md via GitLocalize

* Japanese Translation: ja/data.md (#25)

* Translate data.md via GitLocalize

* Translate data.md via GitLocalize

* Fix typos

* コード内のコメントを日本語に翻訳した

* コード内のコメントの意図をより明確にした

* expose はモジュールとしての公開するという意味なので訳を変更した

* 原文に ... とあるので一応残しておく

* "Client Side Hydration" の翻訳 (#36)

* Translate hydration.md via GitLocalize

* Translate hydration.md via GitLocalize

* Japanese Translation: ja/head.md (#33)

* Translate head.md via GitLocalize

* Translate head.md via GitLocalize

* expose はモジュールとして公開するという意味なので公開という言葉を使うようにした

* コードのコメントの翻訳が漏れていた

* Japanese Translation: ja/routing.md (#38)

* Translate routing.md via GitLocalize

* Translate routing.md via GitLocalize

* Japanese Translation: ja/caching.md (#37)

* Translate caching.md via GitLocalize

* Translate caching.md via GitLocalize

* translated the "source code structure" into Japanese. (#26)

* Translate structure.md via GitLocalize

* Translate structure.md via GitLocalize

* Translate structure.md via GitLocalize

* Japanese Translation: ja/SUMMARY.md (#35)

* Translate SUMMARY.md via GitLocalize

* hydration.md と合わせた

"Client Side Hydration" の翻訳 by hikimon · Pull Request #36 · open-source-translators/vue-ssr-docs
open-source-translators#36

* en/ に合わせてインデントを 2 にした

* Renderer 生成時の各オプションの階層を下げた。en/ でもそうなっている

* Japanese translation: readme.md (#39)

* Translate README.md via GitLocalize

* Translate README.md via GitLocalize
@romandrahan
Copy link

romandrahan commented Dec 2, 2017

@jazoom

make them child routes in the router

I'm afraid it looks like hack. I suppose, there must be another workaround, when components is registered in normal way, without adding them to the child routes?

@yyx990803, is there more elegant solution for that?

@LennonChin
Copy link

LennonChin commented Apr 28, 2018

I have a hack way to solve this problem, recursive query sub components and pre-fetching their datum, just like code:

// entry-server.js
import { createApp } from './app'
export default context => {
  return new Promise((resolve, reject) => {
    const { app, router, store } = createApp()
    router.push(context.url)
    router.onReady(() => {
      const matchedComponents = router.getMatchedComponents()
      if (!matchedComponents.length) {
        return reject({ code: 404 })
      }
      // used to load Promises
      const targetPromises = [];
      // encapsulate pre-fetch datum function
      const doAsyncData = (component) => {
        if (component.asyncData) {
          targetPromises.push(component.asyncData({
            store,
            route: router.currentRoute
          }));
        }
      };
      // recursive query sub components
      const recursive = (component) => {
        doAsyncData(component);
        if (component.components) {
          Object.keys(component.components).forEach(key => {
            recursive(component.components[key]);
          });
        }
      };
      // call asyncData() in all matched componets
      matchedComponents.map(component => {
        recursive(component);
      });
      Promise.all(targetPromises).then(() => {
        context.state = store.state
        resolve(app)
      }).catch(reject)
    }, reject)
  })
}

but there may be performance issues with this approach, need to discuss.

@ozguruysal
Copy link

I was thinking the same solution as @LennonChin but rather then making it recursive just go one level deep. @LennonChin were you able to find another solution or what did you end up with?

@LennonChin
Copy link

LennonChin commented May 28, 2018

@ozguruysal
Use the code I pasted up can recursive the whole levels, then if you use this way you should designate the name option for your custom component to avoid infinite recursion conducting out-of memory problem. the improved code:

return new Promise((resolve, reject) => {
  const {app, router, store} = createApp();
  router.push(context.url);
  router.onReady(() => {
    const matchedComponents = router.getMatchedComponents();
    if (!matchedComponents.length) {
      return reject(new Error('no component matched'));
    }
    // in order to load all promises
    let targetPromises = [];
    // this cache is used to record operated components' keys, avoid infinite recursion
    let keyCache = [];
    const doAsyncData = (component) => {
      if (component.asyncData) {
        targetPromises.push(component.asyncData({
          route: router.currentRoute,
          store
        }));
      }
    };
    const recursive = (component, key) => {
      // if has key, recursived
      if (keyCache.indexOf(key) !== -1) return;
      // cache key
      keyCache.push(key);
      // do async data
      doAsyncData(component);
      // query sub components
      if (component.components) {
        Object.keys(component.components).forEach(key => {
          recursive(component.components[key], key);
        });
      }
    };
    matchedComponents.map(component => {
      recursive(component, component.name);
    });
    Promise.all(targetPromises).then(data => {
      targetPromises = [];
      keyCache = [];
      context.state = store.state;
      resolve(app);
    }).catch(error => {
      targetPromises = [];
      keyCache = [];
      reject(app);
    });
  }, reject);
});

@ozguruysal
Copy link

@LennonChin thanks for sharing.

@mach-kernel
Copy link

mach-kernel commented Jun 8, 2018

The way I went about this was a little bit different. vue-router lets us define props, so in the routes definition something like this can be done:

    {
      path: '/foo/bar',
      component: () => import('...'),
      props: {
        asyncDataHooks: [
          'MyModule/fetchThing'
        ]
      }
    }

Then, in the server entry point:

    let hooks = router.currentRoute.matched.reduce((hooks, cur) => {
      let adh = cur.props.default.asyncDataHooks;
      if (!adh) return hooks;
      return hooks.concat(adh);
    }, []);

    Promise.all(hooks.map((h) => store.dispatch(h)))...

@darkiron
Copy link

good solution but have two question:
how init store in subComponent asyncDate ?
and:
how fetch data action and return one Promise ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants