Giter Site home page Giter Site logo

Async data in nested component about nuxt.js HOT 15 CLOSED

nuxt avatar nuxt commented on April 28, 2024
Async data in nested component

from nuxt.js.

Comments (15)

danieloprado avatar danieloprado commented on April 28, 2024 4

@Xowap Can you provide an example how implement it? thanks πŸ˜„

from nuxt.js.

Atinux avatar Atinux commented on April 28, 2024

Actually it is not possible because it's not linked to a route, Nuxt.js surcharges the component data() associated to a route to allow async data.

For sub components, there are 2 ways of achieving it:

  1. Making the API call in the mounted() hook and setting the data afterwards, downside: no server rendering
  2. Making the API call in the data() of the page component and giving the data as a prop to the subComponent: server rendering OK. But the data() of the page might be less readable because it's loading the async data of the sub components

It all depends if you want the sub components to be server-rendered or not.

I hope it solves your issue :)

from nuxt.js.

Xowap avatar Xowap commented on April 28, 2024

This is kind of what I feared.

I've been reading Vue 2's documentation, it looks like Vuex becomes basically mandatory. Which also solves this problem. I guess the real clean solution is to use Vuex, right?

from nuxt.js.

Atinux avatar Atinux commented on April 28, 2024

Yes of course I forgot about vuex, you can integrate the store easily with Nuxt.js, just add a store/index.js (look at examples/vuex-store)

from nuxt.js.

visualcookie avatar visualcookie commented on April 28, 2024

An example would really help.

from nuxt.js.

Etheryte avatar Etheryte commented on April 28, 2024

@Atinux Could you elaborate why this is not possible? All the components should be known beforehand statically and it should be possible to make the appropriate calls with the given context. I'm looking into how to solve the issue myself, too, as it would tremendously improve modularization.

from nuxt.js.

Atinux avatar Atinux commented on April 28, 2024

Hi @Etheryte

Sadly, there is no way to know the component three inside lib/app/server.js, I can only get the routes components and update them by calling the asyncData & fetch methods. I tried to find a way for it but it seems impossible right now.

But it's also a good thing to not call asyncData for "normal" components since it let's everyone create Vue component compatible with the same behaviour under nuxt.js and a basic vue app.

from nuxt.js.

pea3nut avatar pea3nut commented on April 28, 2024

Use this function. That will test all child component .fetch and call it.

function fetchDeep(component){
    var originFn =component.asyncData;
    component.asyncData =async function (ctx) {
        if(component.components){
            let childComponents =Object.values(component.components);
            console.log(childComponents);
            while(childComponents.length){
                let comp =childComponents.shift();
                if(comp.options.fetch) await comp.options.fetch(ctx);
                if(comp.components) childComponents.push(...Object.values(comp.components));
            }
        };

        return originFn(ctx);
    };
    return component;
};

There is an example:

A nav component.

import Vue from "vue"
import {mapGetters} from "vuex"
import Component from 'nuxt-class-component';

@Component({
    name :'blog-nav',
    async fetch({store}){
        await store.dispatch('fetchCategory');
    },
    computed :{
        ...mapGetters(['categoryMap']),
    },
})
export default class extends Vue {
    showCategory =['technology','works','think'];
}

A page component which import nav component.

import Vue from "vue"
import Component from 'nuxt-class-component';
import {ArticleInfo} from "@foxzilla/fireblog";
import Marked from 'marked';
import Nav from '~/components/blog-nav.vue';
import {fetchDeep} from '~/modules/jslib';


@Component(fetchDeep({ // ❗️❗️❗️
    async asyncData(ctx){
        var articleInfo:ArticleInfo =await ctx.app.$axios.$get(`/article/detail/${ctx.params.id}`);
        await (<any>Nav).options.fetch(ctx);
        return {articleInfo}
    },
    head(val:ArticleInfo){
        return {
            title: this.articleInfo.title,
        };
    },
    components :{
        'blog-nav' :Nav,
    },
}))
export default class extends Vue {
    articleInfo:ArticleInfo;
    md:(mdContent:string)=>string =Marked;
}

from nuxt.js.

pea3nut avatar pea3nut commented on April 28, 2024

Use this function. That will test all child component .fetch and call it.

export function fetchDeep(component){
    var originFn =component.asyncData;
    var fetchedComp =[];
    component.asyncData =async function (ctx) {
        if(component.components){
            let childComponents =Object.values(component.components);
            while(childComponents.length){
                let comp =childComponents.shift();
                if(fetchedComp.includes(comp))continue;
                else fetchedComp.push(comp);
                if(comp.options && comp.options.fetch) await comp.options.fetch(ctx);
                if(comp.fetch) await comp.fetch(ctx);
                if(comp.components) childComponents.push(...Object.values(comp.components));
                if(comp.options && comp.options.components) childComponents.push(...Object.values(comp.options.components));
            }
        };

        return originFn && originFn(ctx);
    };
    return component;
};

There is an example:

A nav component.

import Vue from "vue"
import {mapGetters} from "vuex"
import Component from 'nuxt-class-component';

@Component({
    name :'blog-nav',
    async fetch({store}){ // will be called
        await store.dispatch('fetchCategory');// use vuex
    },
    computed :{
        ...mapGetters(['categoryMap']),
    },
})
export default class extends Vue {
    showCategory =['technology','works','think'];
}

A page component which import nav component.

import Vue from "vue"
import Component from 'nuxt-class-component';
import {ArticleInfo} from "@foxzilla/fireblog";
import Nav from '~/components/blog-nav.vue';
import {fetchDeep} from '~/modules/jslib';


@Component(fetchDeep({ // ❗️❗️❗️
    async asyncData(ctx){
        var articleInfo:ArticleInfo =await ctx.app.$axios.$get(`/article/detail/${ctx.params.id}`);
        await (<any>Nav).options.fetch(ctx);
        return {articleInfo}
    },
    components :{
        'blog-nav' :Nav,
    },
}))
export default class extends Vue {
}

from nuxt.js.

Etheryte avatar Etheryte commented on April 28, 2024

@pea3nut Does this work with SSR as well? I tried a similar approach a few releases ago and had a ton of problems getting it to work on the server side.

from nuxt.js.

pea3nut avatar pea3nut commented on April 28, 2024

@Etheryte It doesn't have a strong test, but now it works on npm run dev very well, not only enter a URL but also passing in by <router-link></router-link>, and, I have tested npm run generate just now, it works too.

Of course, my app is not complex enough now, maybe some bug hidden is there.
`

from nuxt.js.

Romick2005 avatar Romick2005 commented on April 28, 2024

I've updated your function with possibility to leave empty fetch or asyncData component property and also use both fetch or asyncData on chold components:

export const fetchDeep = function (component) {
  const originFn = component.asyncData;
  component.asyncData = async function (ctx) {
    if (component.components) {
      const promisesToResolve = [];
      let childComponents = Object.values(component.components);
      while (childComponents.length) {
        let comp = childComponents.pop();
        if (comp.asyncData) {
          promisesToResolve.push(comp.asyncData(ctx));
        }
        if (comp.fetch) {
          promisesToResolve.push(comp.fetch(ctx));
        }
        if (comp.components) {
          childComponents.push(...Object.values(comp.components));
        }
      }
      await Promise.all(promisesToResolve);
    };
    return (originFn && originFn(ctx)) || Promise.resolve();
  };
  return component;
};

Is it correct that collecting all promises to resolve in array and then call Promise.all theoretically would work faster that couple of await? On it doesn't matter on server side render? And is it correct assumption that component promise resolve order is unimportant in such case?

from nuxt.js.

pea3nut avatar pea3nut commented on April 28, 2024

@Romick2005 I found some bugs in my fetchDeep, and I guess you fetchDeep has there bugs too.

export function fetchDeep(component){
    var originFn =component.asyncData;
    var fetchedComp =[];
    component.asyncData =async function (ctx) {
        if(component.components){
            let childComponents =Object.values(component.components);
            while(childComponents.length){
                let comp =childComponents.shift();
                if(fetchedComp.includes(comp))continue;
                else fetchedComp.push(comp);
                if(comp.options && comp.options.fetch) await comp.options.fetch(ctx);
                if(comp.fetch) await comp.fetch(ctx);
                if(comp.components) childComponents.push(...Object.values(comp.components));
                if(comp.options && comp.options.components) childComponents.push(...Object.values(comp.options.components));
            }
        };

        return originFn && originFn(ctx);
    };
    return component;
};

It's a little ugly... and too hackly.

from nuxt.js.

pea3nut avatar pea3nut commented on April 28, 2024

And, I'm no idea of how to use the async data in the component of /layouts. Does anyone have some ideas?

from nuxt.js.

lock avatar lock commented on April 28, 2024

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

from nuxt.js.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.