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 ishttp://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:
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
.