Search code examples
typescriptvue.jsnuxt.jsapolloserver-side-rendering

How to set Nuxt SSR async metadata in a typescript class component? Fetching using Apollo


I am trying to set page metadata in Nuxt after fetching data, but doing so inside of a class component. To make matters worse I am fetching using Apollo. There are plenty of examples for using asyncData such as here, and the documentation has information on fetching. However, I am finding that 1) I cannot access the data, or 2) I cannot use this.$apollo.query, if doing either of these inside of a class component. Here is what I have so far based on SO answers and documentation.

Problem with Apollo:

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component({
  head(): Record<string, unknown> {
    return { title: this.response.title }
  },
  async asyncData(): Promise<any> {
    const response = this.$apollo.query({ // <-- does't work
      query: SITE_PAGE,
      variables: {
        path: this.$route.path
      }
    });
    return { response }
  },
})
export default class StandardPage extends Vue {}
</script>

If I just hit a the server instead of Apollo to get data, here is the problem with accessing the data:

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component({
  head(): Record<string, unknown> {
    return { title: this.response.title } // <-- cant access response below / undefined
  },
  async asyncData({ params, $http }) {
    const response = await $http.$get(`https://<myserverapi>/getpage`)
    console.log(response.title) // <--got data along with title
    return { response }
  }
})
export default class StandardPage extends Vue {}
</script>

Could someone please tell me what I am doing wrong or what else I need?


Solution

  • In order to access the data you need to put this: YOUR_CLASS_NAME in the head constructor.

    In order to use Apollo you can get access to that by passing in context to asyncData.

    The final code would look like this:

    <script lang="ts">
    import { Component, Vue } from 'vue-property-decorator'
    
    @Component({
      head(this: StandardPagePage): Record<string, unknown> { // <-- added this:StandardPage
        return { title: this.response.title }
      },
      async asyncData(context): Promise<any> { // <-- added context
    
        // call to Apollo now looks like this:
    
        const client = context.app.apolloProvider?.defaultClient
        const response = await client!.query({
          query: SITE_PAGE,
          variables: {
            path: context.route.path,
          },
        })
        return { response }
      },
    })
    export default class StandardPage extends Vue {}
    </script>