Home > Mobile >  Nuxt async fetch() doesn't make server side request on <NuxtLink> but does so on regular
Nuxt async fetch() doesn't make server side request on <NuxtLink> but does so on regular

Time:09-18

As I understand, async fetch() in Nuxt makes server side call before render which I'm trying to use to render post data but I don't understand why <NuxtLink> and <a href... are working differently.

  • <NuxtLink> works to render content if url in async fetch /api/readpost/.. is used but it renders before finishing fetching /api/readpost, so the error 404 post flashes before updating after the data shows up
  • <a href... works correctly if url in async fetch is http://spserver:3002/api/readpost/... and correctly waits for the fetch before rendering

Client and server request urls would be different because the project is running in docker behind nginx. My concern here is to always make sure the data shows up before rendering happens and if possible make <NuxtLink> behave the same way regular <a href.. seems to be working.

So, what is causing the difference, how would I ensure async fetch always makes server side request and waits for data before rendering?


Video demo:

video demo 1

On page reload I get console errors like this:

Error: connect ECONNREFUSED 127.0.0.1:80
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1159:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 80,
  config: {
    url: '/api/readpost/23',
    method: 'get',
    headers: {
...

Code:

I have something like this in a nuxt page to render post data:

<template>
<template v-if="posts && posts.length">
  <PostRender :post="posts[0]" />
</template>
<div v-else-if="!$fetchState.pending">
404 POST NOT FOUND, PLEASE DOUBLE CHECK THE URL
</div>
</template>

<script>
  export default {
    data() {
      return {
          postid : this.$route.params.post,
          posts : null,
      }
    },
    async fetch()
    {
        let res = await this.$axios({
          method : 'GET',
          url : '/api/readpost/'   this.postid
        });

        this.posts = res.data;
    }
</script>

and this lists the posts and links

<template>
<div>
<div v-for="p in posts">
  <NuxtLink :to="'/post/'   p.id">NuxtLink</NuxtLink>
<hr>
</div>
</div>
</template>

<script>
  export default {
    data() {
      return {
        posts : null
        }
      },
    mounted() {
        this.$axios({
          method : 'GET',
          url : '/api/readlatest'
        })
        .then((res) =>
        {
            this.posts = res.data;
        })
        .catch((err) =>
        {
            console.error(err);
        });
    }
  }
</script>

And my docker compose looks something like this

version : "3"
services:
  spserver:
    build: .
    container_name: spserver
    working_dir: /app
    volumes:
      - ./server/:/app
    ports:
      - 7002:3002
    entrypoint: npm run dev
  spclient:
    image: node:14.18.1-alpine
    container_name: spclient
    working_dir: /app
    volumes:
      - ./client/:/app
    environment:
      - PORT=3001
      - HOST=0.0.0.0
      - "BASE_URL=/"
    entrypoint: sh -c "npm run build && npm run dev"
    depends_on:
      - spserver
  spnginx:
    image: nginx:1.18-alpine
    container_name: spnginx
    volumes:
      - ./nginx.conf/:/etc/nginx/nginx.conf
    ports:
      - 9001:80
    depends_on:
      - spclient
      - spserver

Relavant bit of nuxt.config.js:

axios: {
  baseURL: process.env.BASE_URL
},

Versions:

"nuxt": "^2.15.8",
"@nuxtjs/axios": "^5.13.6",

This solved my issue, although a little confused about the whole thing still:

url : (process.server ? 'http://spserver:3002/api/readpost/' : '/api/readpost/')   postid

CodePudding user response:

Nuxt is isomorphic but will make a call to the server only on the initial render. That one will be generated on the server (supposing ssr: true) and will be sent to your browser.

There, you will only get client-side navigation on any successful route changes thanks to Vue router.

If you use an a tag, you will be nuking your whole Nuxt/Vue app and creating a brand new from scratch, hence have another backend generation (clearly not the way to go as you can guess).

If you want to have an example of data fetching using fetch() (lifecycle hook), you can check this answer. It can also be done in a blocking way by using the asyncData().

PS: I recommend you using the ones above rather than created() and mounted() in a Nuxt app try to use async/await all the time rather than a mix between those .then.

  • Related