Nuxt 3 SSR: useFetch() returning null on page refresh
Asked Answered
M

17

19

(After having edited my original question many times over, I have decided to completely rework it as to make it more clear and succinct. This is in accordance with StackOverflow recommendations.)

The setup:

Create a new Nuxt 3 project:

pnpm dlx nuxi init test-project
cd test-project
pnpm i
pnpm run dev -o

Edit app.vue like this:

<script setup>
const { data: thing } = useFetch("http://localhost:8000/things/1").then(res => {
  console.log(res)
  return res
})
</script>

<template>
  <div>
    <p>{{ thing }}</p>
  </div>
</template>

I added the console.log-statement to track where fetching takes place.

No changes made to the config. It is my understanding that Nuxt 3 defaults to SSR.

The issue:

Two scenarios:

I. When making alterations to the code in app.vue and thus triggering HMR thing will contain the expected data from the API.

II. However, when refreshing the page in the browser thing will be null. The paragraph-tag will be empty.

My observations:

  • The same behavior applies for useAsyncData().
  • Everytime I trigger HMR (scenario I.) the client makes a request to the API and successfully receives the data (as can be seen in the network tab of the developer tools).
  • Whenever I refresh the page in the browser (scenario II.), I receive both one console log in the terminal and one in the browser console. Both contain an error with status code 500 and message "fetch failed ()". However, according to the network tab, no client-side request has been made.
  • If I use $fetch instead, it will log the same error to the terminal. However, while the request fails server-side, it successfully tries again client-side and thus the API data will be displayed on the page.

My conclusions so far:

It seems to me, that all server-side requests fail and all client-side requests succeed.

When $fetch fails server-side, it throws an error and tries again on client-side. This is what I'd expect. However, useFetch and useAsyncData don't behave this way. Instead, the error is written to the response object and no client-side request is made. (This is not a major problem though, since I can check the error-entry in the response object and make another request on client-side if needed.)

Open questions:

Why do all server-side requests fail? I understand that the Nuxt-server does not have access to the browser and therefore cookies and such. But these are simple GET requests to a locally hosted Laravel API that doesn't require authentication. They shouldn't need CSRF- or session-cookies to be successful. I can make a successful request to the API route with Postman without cookies.

Is this due to me doing something wrong? Or is this expected behavior in development mode (pnpm run dev)? I never had this issue with Nuxt 2.

I am afraid, I am missing something obvious.

Thank You!

Musquash answered 11/12, 2022 at 9:56 Comment(7)
Which exact version of Nuxt are you using?Opium
I am not sure, if this is exact enough, but it is [email protected]. I installed it yesterday according to documentation using the command "pnpm dlx nuxi init <project-name>". If you need more specific version information, please let me know how to obtain it.Musquash
@Opium I created a new and very basic project to make sure this behavior is not the result of some configuration or package or something. The behavior remains the same (see edit).Musquash
@Opium I have the same issue "nuxt": "3.0.0-rc.12", sometimes useFetch() returns nullRaillery
I can actually confirm this issue for myself as well. I'm using an api proxy to handle filtering and authentication, which works perfectly fine when called directly. Accessing /api/data loads my data from the upstream API, and returns it as JSON. On initial load, I receive nothing from the API. When navigating to home, and back to the page that has the useFetch via nuxt-links, it loads my data. At least, in the console. My v-for loop isn't working either, and still shows no actual lines in my page. This setup is running Nuxt 3.0.0 with Nitro 1.0.0 on Node 18.Florella
Can confirm this. But ... even weirder ... if I do an arbitrary useFetch on one line, then do my intended request second, the first will be null and the second useFetch will be valid. Adding in a 100ms delay (setTimeout) allows the useFetch to execute. Seems to be a timing thing.Slightly
strange thing is that for me, it works locally but when I deploy to server I have this problem, so dev build is fine, I'm so confused :(Disharmony
P
12

wire417.

Try to change your API address from "localhost" to "127.0.0.1" in useFetch request. It may help you.

Pamper answered 22/1, 2023 at 11:34 Comment(1)
I used 'localhost' in my url and had the same problem. If I use the appropriate ip instead, everything works.Undesigning
T
6

I had the same issue with nuxtjs v3.1.2 (current version). It seems to be a timing issue indeed. I got it working by wrapping the useFetch function in the nextTick funtion:

export default {
mounted(): {
   this.$nextTick(async () => {
      const {data, pending, error, refresh } = await useFetch('/...')
   }

}

or if you're using script setup

<script setup>
import { nextTick } from 'vue'

await nextTick()

const {data, pending, error, refresh } = await useFetch('/...')

</script>
Tambourin answered 6/2, 2023 at 13:6 Comment(1)
I think using nextTick() before useFetch will result in no data fetching at all on the server side. The data fetching will happen only on client side. You can check that for your self by putting a console.log(data) after the useFetch and check the terminal output.Web
S
4

[UPDATE NODEJS]

I got the same error as you, my API is not protected and complete public, but also can't get data on SSR page load.

It took me 1 day to search for the error, but maybe this is how to solve my problem, hope it helps you:

Update the latest NodeJS LTS version here: https://nodejs.org/en/

I updated NodeJS version from 18.12 to 18.13. And my problem was completely solved.

Stalag answered 9/1, 2023 at 10:3 Comment(1)
🏆 This fixed it for me. Thank you! useAsyncData on v18.12 refused to run on the server and would only trigger after load.Griffiths
A
3

Try switching to Node v16.

I've been battling the same problem for two days - useFetch() and useAsyncData() would only work if I turned SSR off by setting ssr: false in nuxt.config.ts, otherwise it would return null on page load. I was using the latest current Node version, tried the latest LTS version and it didn't work either. None of the answers here have helped. Then I decided to try running it under Node v16 and it worked like a charm. Some resources online say Nuxt 3 works best with either Node v14 or v16, and it seems to be the case for Nuxt 2 as well by the way.

Affable answered 27/2, 2023 at 11:37 Comment(1)
Can confirm, had the same problems with 3.0.0 and solved it this way. Thank god for nvmCategorize
G
3

I was having exactly the same issue in nuxt 3 using nextTick solve your issue.

<script setup>
import { nextTick } from 'vue'

onMounted(() => {
  nextTick(async () => {
    const { data } = await useFetch("/data", { baseURL: "http://localhost:8000/api" })
    //
  })
})
</script>
Grishilde answered 21/3, 2023 at 6:53 Comment(0)
E
2

Here is an example how you could solve your issue using nextTick:

onMounted(() => {
  nextTick(async () => {
    const { data } = await useFetch("/services", { baseURL: "http://localhost:8000/api" })

    services.value = data.value.services
  })
})

note i'm using composition api.

Engaged answered 7/2, 2023 at 19:27 Comment(1)
I think using nextTick() before useFetch will result in no data fetching at all on the server side. The data fetching will happen only on client side. You can check that for your self by putting a console.log(data) after the useFetch and check the terminal output.Web
M
1

Check if the api is accessible through node, not through the browser or postman. I was having exactly the same issue when using ssr. The problem was due to node ssl error UNABLE_TO_VERIFY_LEAF_SIGNATURE. After I fixed it it started working as expected.

const { data: data } = await useFetch('https://api.your-domain.com/content/1', {
  onRequestError({ request, options, error }) {
    // Handle the request errors
    console.log(error); // check if there are any errors in the terminal
  },

})

console.log(data.data); // this was undefined due to the node cert error
Metempsychosis answered 25/2, 2023 at 16:58 Comment(0)
T
1

As I understand, there is a issue in Nuxt3 with Suspense feature from Vue (for me in combination with transitions), there is a big thread about it here https://github.com/nuxt/nuxt/issues/13471 and a PR in Vue core here https://github.com/vuejs/core/pull/5952

There is different types of workarounds while waiting for a fix, I'm using nextTick (as suggested by Youssef El gharib and Farzad Jafari) in my onMounted hook which does the job for me, hoping for a official fix soon. Someone made a workaround as a composable here https://github.com/nuxt/nuxt/issues/13471#issuecomment-1449898517

Transmit answered 9/7, 2023 at 11:3 Comment(0)
M
0

Make sure your api is accessible. You can add const { data, error } = useFetch(...) to see what happens.

nuxt 3.0.0 will still work properly with your app

Mcnair answered 11/12, 2022 at 14:53 Comment(4)
As to your suggestion: Maybe take another look at my question. It clearly states that the data is successfully fetched from the client (see scenario I.). Therefore, the API is accessible. I also tested the API using Postman.Musquash
Oh sorry I thought you downvoted my answer. I'm pretty sure your API is not accessible at least from the localhost domain. Show the error variable to knowMcnair
Thank you for still trying to help me! I still am convinced that the API is accessible. 1. I tested the API using Postman. 2. I can access the API by entering the URL in the browser. 3. All fetches from the client to the API succeed and return the expected data. So, I am sure that the API is accessible (at least to the client). Only requests from Nuxt's server-side-rendering are failing. When they fail, the error message was just "fetch failed ()" with status code 500. No more information, sadly.Musquash
Just to be clear: The error message I mentioned is from the error-property returned from useFetch().Musquash
J
0

I've run into the same issue, I did try a couple of the workarounds like setting a timeout or an arbitrary useFetch() (as suggested by Turukawa in comments) but success still varied.

I did find using $fetch instead seems to be stable and works as expected.

Edit: I had also tried updating to Node v 18.13.0, but it did not fix the issue.

Jensen answered 9/1, 2023 at 20:33 Comment(0)
H
0

I downgraded my node version to 16 and surprisingly it started to work as expected. Before that, I thought it was something I had done or messed up. I struggled with this long enough to say that I tried almost everything else under the sun and that this is one of the reasons it may not work, but I don't know why. My OS is Windows btw.

Heinrick answered 13/4, 2023 at 13:15 Comment(0)
C
0

Your code doesn't make much sense in JavaScript syntax.

You are trying to deconstruct a promise with const { data: thing } = useFetch("http://localhost:8000/things/1").then(res => { console.log(res) return res })'

This code will work:

<script setup>
const { data: thing } = await useFetch("/things/1")
</script>

<template>
  <div>
    <p>{{ thing }}</p>
  </div>
</template>
Cirillo answered 9/7, 2023 at 12:10 Comment(0)
M
0

Seems like the refresh method inside a watchEffect does the job

const { data: res, refresh } = await useFetch<IApiResult<ISite>>(`${url}/api/sites/${route.params.routename}`)
const site = computed<ISite|undefined>(() => res.value?.data)

watchEffect(() => {
    // maybe could add some sort of req success validation
    if(!site.value) refresh()
})
Mukden answered 26/8, 2023 at 23:56 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Hawkins
P
0

useFetch not work on nuxt 3.9.0 / node 20.10 with SSR, but useAsyncData works

Pinkston answered 6/1, 2024 at 11:32 Comment(0)
E
0

Use node v16, this issue is happend in node v18

Echols answered 1/3, 2024 at 12:53 Comment(0)
B
0

After investing numerous hours, I have identified both the cause of this issue and its solution. Avoid utilizing nextTik() before invoking useFetch, as it triggers fetching client-side rendering (CSR), causing you to forfeit SEO benefits (resulting in no fetched data in server-side rendering (SSR) mode on the source page).

To resolve this issue promptly, simply upgrade the version of your Nuxt installation:

npx nuxi upgrade

The version that has proven effective for me is "nuxt": "^3.10.3".

Bravado answered 10/3, 2024 at 9:2 Comment(0)
C
0

I had the same issue, I tried to fix it for hours. I just wrapped my function in a 'next tik' as suggested and it fixed it! good call! I don't know what causes that but it's infuriating and very hard to debug. this was the only article that has talked about that I have been able to find. unfortunately it seems you have to search just the right thing to find this question on google.

Cleistogamy answered 4/7, 2024 at 1:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.