'How to access a injected repository from a component's method

Lets say we injected this repository on a plugin/service-container.js

import nodeFetch from 'node-fetch'
import { AbortController as NodeAbortController } from 'node-abort-controller'

import HttpClient from '@/services/httpClient'
import PostRepository from '@/repositories/posts'


export default ({ app }, inject) => {
  if (!process.client || app.context.env.NUXTJS_DEPLOY_TARGET === 'server') {
    inject('postRepository', postRepository)
  }
}

I have always acceded to API repositories from the asyncData method, like so:

export default {
  async asyncData ({ $postRepository,  }) {
    const posts = await $postRepository.getAllPaginated(page, 11)
    return {
      posts,
    }
  }
}

But I need to access to it in a method, this is actually working but:

  • I doesn't look the right way because i'm caching in the component's data()
  • It fires this lint error:

Async method 'asyncData' has no 'await' expression.eslintrequire-await

What's the right way? I Can't find it online (the only examples I found involved using the Store)

export default {
  async asyncData ({ $postRepository }) {
    this.$postRepository = $postRepository 
  },
  methods: {
    async loadMore () {
      if (this.page < this.posts.numPages) {
        const posts = await this.$postRepository.getAllPaginated(this.page + 1, 11)
      }
    }
  }
}


Solution 1:[1]

It seems that an injected dependency can be accessed (in this case) with simply this.$postRepository inside any method so I didn't even need that asyncData

Solution 2:[2]

The error is coming from here

async asyncData ({ $postRepository }) {
  this.$postRepository = [missing await here] $postRepository 
},

From the documentation

This hook can only be used for page-level components. Unlike fetch, asyncData cannot access the component instance (this). Instead, it receives the context as its argument. You can use it to fetch some data and Nuxt will automatically shallow merge the returned object with the component data.

Hence, you cannot use any kind of this.loadMore in asyncData because it doesn't have access to the instance yet. So, inject is indeed the proper way of doing things.

With a plugin like that

export default ({ _ }, inject) => {
  inject('customTest', async () => {
    const response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
    return await response.json()
  })
}

And a page like this

<template>
  <div>
    <pre>item: {{ item }}</pre>
  </div>
</template>

<script>
export default {
  async asyncData({ $customTest }) {
    const item = await $customTest()
    return { item }
  },
}
</script>

It is not calling a method but you could totally use this.$nuxt.refresh() to fetch it again and increment the index of the repository call after an update in the store.
Which could be referenced like

await fetch(`https://jsonplaceholder.typicode.com/todos/${indexFromVuex}`)

You could of course keep it local too

<template>
  <div>
    <pre>item: {{ item }}</pre>

    <button @click="fetchNewItem">fetch new item</button>
  </div>
</template>

<script>
export default {
  async asyncData({ $customTest }) {
    const item = await $customTest()
    return { item }
  },
  data() {
    return {
      index: 1,
    }
  },
  methods: {
    async fetchNewItem() {
      this.index += 1
      this.item = await this.$customTest(this.index)
    },
  },
}
</script>

So yeah, I don't think that there are other possible approaches with asyncData.
The fetch() hook is a bit more flexible but it's also totally different too regarding how it is working.
Anyway, with those 2 approaches you could totally have enough to solve the issue of your HTTP call.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 kissu