13

(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!

wire417
  • 150
  • 1
  • 12
  • Which exact version of Nuxt are you using? – kissu Dec 11 '22 at 11:55
  • I am not sure, if this is exact enough, but it is nuxt@3.0.0. I installed it yesterday according to documentation using the command "pnpm dlx nuxi init ". If you need more specific version information, please let me know how to obtain it. – wire417 Dec 11 '22 at 12:08
  • @kissu 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). – wire417 Dec 11 '22 at 13:00
  • @kissu I have the same issue `"nuxt": "3.0.0-rc.12",` sometimes `useFetch()` returns `null` –  Dec 13 '22 at 00:30
  • 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. – ZeroThe2nd Dec 23 '22 at 15:33
  • 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. – Turukawa Jan 04 '23 at 13:01

13 Answers13

6

wire417.

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

  • I used 'localhost' in my url and had the same problem. If I use the appropriate ip instead, everything works. – rttmax May 03 '23 at 08:43
3

[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.

KHANH V.O
  • 31
  • 3
  • This fixed it for me. Thank you! useAsyncData on v18.12 refused to run on the server and would only trigger after load. – Brandon Mar 05 '23 at 19:39
3

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>
Nico Engel
  • 31
  • 2
  • 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. – Stefan Jul 14 '23 at 07:53
2

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>
F. Müller
  • 3,969
  • 8
  • 38
  • 49
1

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.

  • 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. – Stefan Jul 14 '23 at 07:54
1

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.

Alexander
  • 631
  • 1
  • 8
  • 19
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

Tachibana Shin
  • 2,605
  • 1
  • 5
  • 9
  • 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. – wire417 Dec 11 '22 at 15:28
  • 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 know – Tachibana Shin Dec 12 '22 at 16:12
  • 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. – wire417 Dec 12 '22 at 21:02
  • Just to be clear: The error message I mentioned is from the `error`-property returned from `useFetch()`. – wire417 Dec 12 '22 at 21:26
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.

0

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
Cholakov
  • 31
  • 1
  • 4
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.

0

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

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>
learntheropes
  • 444
  • 3
  • 11
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()
})
  • 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](/help/how-to-answer). – Community Aug 28 '23 at 20:21