1

I tried to get data from api with params which come from an argument in a v-for. In findUser method, I can console.log the data I'm looking for. But I can't get it at the end of findUser, why?

I know there is an async method to get it but I don't understand how to manage it to make it work with what I want to do; I also thought about calling the two API at the same time, but the result is the same, I don't know how to manage it.

<template>
  <div>
    <h4>Listes Reçues</h4>
    <p v-for="element in results" id="flex-list" :key="element.list_id">
      {{ element.list_name }} de {{ findUser(element.user_id) }}
    </p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      results: '',
      nickname: '',
    }
  },
  created() {
    this.$axios
      .get(`/api/listReceived/${this.$auth.user[0].user_id}`)
      .then((res) => {
        this.results = res.data
        console.log(JSON.stringify(this.results))
      })
      .catch((err) => {
        console.error(err)
      })
  },
  methods: {
    findUser(id) {
      console.log(id)
      let data = ''
      this.$axios
        .get(`http://localhost:3000/api/userdata/${id}`)
        .then((res) => {
          data = res.data[0].nickname
          console.log(data)
        })
        .catch((err) => {
          console.error(err)
        })
      return data
    },
  },
}
</script>
kissu
  • 40,416
  • 14
  • 65
  • 133
Bpio
  • 23
  • 4

2 Answers2

1

created() is totally fine with Vue but usually you do use fetch() and asyncData() hooks in Nuxt.
Here is the basic idea using JSONplaceholder's API.

Here is a possible /pages/index.vue

<template>
  <div class="flex flex-col items-center">
    <h1 class="p-4 bg-green-700 rounded-md">
      List of users from JSONplaceholder
    </h1>
    <section class="mt-4">
      <p v-for="user in users" :key="user.id">
        {{ user.name }}  {{ user.email }} ~
        <nuxt-link
          :to="{ name: 'users-id', params: { id: user.id } }"
          class="border-b-4 border-green-500"
        >
          Check details
        </nuxt-link>
      </p>
    </section>
  </div>
</template>

<script>
export default {
  name: 'Index',
  data() {
    return {
      users: [],
    }
  },
  async fetch() {
    this.users = await this.$axios.$get('/users')
  },
}
</script>

<style>
* {
  @apply bg-gray-800 text-gray-100;
}
</style>

And the detailed page aka /pages/users/_id.vue using the fetch() hook.

<template>
  <div class="flex flex-col items-center">
    <nuxt-link class="p-4 bg-purple-700 rounded-md" :to="{ name: 'index' }">
      Go back
    </nuxt-link>

    <h2>User details ID: # {{ $route.params.id }}</h2>
    <p v-if="$fetchState.pending">Loading user's info...</p>
    <p v-else-if="$fetchState.error">Error while fetching user</p>
    <div v-else>
      <p>{{ user.name }}</p>
      <p>{{ user.phone }}</p>
      <p>{{ user.website }}</p>
      <p>{{ user.company.name }}</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'UserId',
  data() {
    return {
      user: {},
    }
  },
  async fetch() {
    this.user = await this.$axios.$get(`/users/${this.$route.params.id}`)
  },
}
</script>

I do prefer this approach because it's not blocking the render, you can add some smooth skeleton to still let the user know that something is happening. On top of that, fetch() is available on both components and pages while asyncData() is only for pages.
It also gives the nice $fetchState helper that can also be quite handy!


Here is the same /pages/users/_id.vue page using the asyncData() hook.

<template>
  <div class="flex flex-col items-center">
    <nuxt-link class="p-4 bg-purple-700 rounded-md" :to="{ name: 'index' }">
      Go back
    </nuxt-link>

    <p>{{ user.name }}</p>
    <p>{{ user.phone }}</p>
    <p>{{ user.website }}</p>
    <p>{{ user.company.name }}</p>
  </div>
</template>

<script>
export default {
  name: 'UserId',
  async asyncData({ route, $axios }) {
    const user = await $axios.$get(`/users/${route.params.id}`)
    return { user }
  },
}
</script>

Main benefit of using asyncData is the fact that it's more safe and that it's blocking the render (can be either a pro or a con, more of a con for me personally).

Here are some other in-depth answers comparing fetch() vs asyncData().
Check out this handy blog article on the subject and also this dev.to clone example.


Finally, if you want to take the SSG path and optimize the whole thing with the least amount of API calls once on the client-side, you can also check my other answer.

kissu
  • 40,416
  • 14
  • 65
  • 133
1

On top of my top answer which was quite not on point regarding the question but still relevant, here is an example on how to handle an intersection properly.

I did not used an endpoint but mocked the data locally in data() hence why I keep my post above.

<template>
  <div class="flex flex-col items-center">
    <h1 class="p-4 bg-green-700 rounded-md">
      List of users ordered by their according message
    </h1>
    <!-- <pre>{{ messages }}</pre> -->
    <section>
      <div v-for="user in groupedMessages" :key="user.id" class="mt-4">
        <p>
          User: <b>{{ user.name }}</b>
        </p>

        <aside>
          Messages:
          <span v-if="!user.messages.length">No messages actually</span>
        </aside>
        <p v-for="message in user.messages" :key="message.id">
          <span class="italic">- {{ message.text }}</span>
        </p>
      </div>
    </section>
  </div>
</template>

<script>
// ES version of lodash, lighter overall
import { cloneDeep } from 'lodash-es'

export default {
  name: 'Index',
  data() {
    return {
      messages: [
        {
          id: 1,
          text: 'Hello world',
          userId: 1,
        },
        {
          id: 2,
          text: 'Nice cool message',
          userId: 1,
        },
        {
          id: 3,
          text: 'Still for the first user?',
          userId: 1,
        },
        {
          id: 4,
          text: 'Yep, apparently...',
          userId: 1,
        },
        {
          id: 5,
          text: "Eh, surprise, I'm a sneaky one...",
          userId: 3,
        },
        {
          id: 6,
          text: 'Oh, a second one.',
          userId: 2,
        },
        {
          id: 7,
          text: "You're damn right!!",
          userId: 2,
        },
      ],
      users: [
        {
          name: 'Patrick',
          id: 1,
          messages: [],
        },
        {
          name: 'Pablo',
          id: 2,
          messages: [],
        },
        {
          name: 'Unkown author',
          id: 5,
          messages: [],
        },
        {
          name: 'Escobar',
          id: 3,
          messages: [],
        },
      ],
    }
  },
  computed: {
    groupedMessages() {
      // we use that to avoid any kind of further mutation to the initial `users` array
      const clonedUsers = cloneDeep(this.users)
      // we do loop on each message and find a corresponding user for it
      this.messages.forEach((message) =>
        clonedUsers.forEach((user) => {
          if (user.id === message.userId) {
            user.messages.push(message)
          }
        })
      )
      return clonedUsers
    },
  },
}
</script>

The github repo is available, please do not pay attention to the unrelated name of it.

This is how it looks on Netlify.

enter image description here

kissu
  • 40,416
  • 14
  • 65
  • 133