nuxt: `rc.5` breaks hydrating `useFetch` data

Environment

  • Operating System: Darwin
  • Node Version: v16.15.0
  • Nuxt Version: 3.0.0-rc.5
  • Package Manager: pnpm@7.5.0
  • Builder: vite
  • User Config: modules, runtimeConfig, kql, typescript
  • Runtime Modules: @vueuse/nuxt@8.9.2, nuxt-kql@0.10.1
  • Build Modules: -

Reproduction

ℹ️ Edit: See minimal reproductions from @KoenCa in the comments below.

Reproduction with nuxt-kql module

Repo (RC 5): https://github.com/johannschopplich/kirby-nuxt-starterkit/tree/feat/nuxt-3-rc.5 👉 Live demo of this repo: https://superlative-gelato-9c9293.netlify.app (Inspect the bug in the console)

Repo (RC 4): https://github.com/johannschopplich/kirby-nuxt-starterkit 👉 Live demo of this repo: https://kirby-nuxt-starterkit.netlify.app

Describe the bug

Server-side fetched data can’t be hydrated in the client. A custom key is passed to useFetch (the same on client & server), but on the client the data for the same key seems not be able to be fetchable.

With disabled build minification, the console (client) throws:

TypeError: data.value is null

In rc.4, everything worked correctly.

Additional context

No response

Logs

👀 View the console error
TypeError: data.value is null
    NuxtJS 63
        setup
        callWithErrorHandling
        setupStatefulComponent
        setupComponent
        mountComponent
        hydrateNode
        hydrateSuspense
        hydrateNode
        hydrateSubTree
        componentUpdateFn
        run
        update
        setupRenderEffect
        mountComponent
        hydrateNode
        hydrateSubTree
        componentUpdateFn
        run
        update
        setupRenderEffect
        mountComponent
        hydrateNode
        hydrateSubTree
        componentUpdateFn
        run
        update
        setupRenderEffect
        mountComponent
        hydrateNode
        hydrateSubTree
        componentUpdateFn
        run
        update
        setupRenderEffect
        mountComponent
        hydrateNode
        hydrateChildren
        hydrateElement
        hydrateNode
        hydrateChildren
        hydrateFragment
        hydrateNode
        hydrateSubTree
        componentUpdateFn
        run
        update
        setupRenderEffect
        mountComponent
        hydrateNode
        hydrateSuspense
        hydrateNode
        hydrateSubTree
        componentUpdateFn
        run
        update
        setupRenderEffect
        mountComponent
        hydrateNode
        hydrate
        mount
        mount
        initApp
        async*
entry-d9af1809.mjs:1091:13

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 10
  • Comments: 15 (7 by maintainers)

Most upvoted comments

Thanks for making reproduction and detailed issues. With RC.5, for the default key instead of generating a hash from dynamic url passed to the useFetch, we auto-generate the key based on static code location where useAyncData, useFetch or useState are used. (#4955)


A hash collision is initial provided reproduction was happening (app.vue-331 and app.vue-385 both resolving to same 875093775). It is fixed in the latest ohash library using secure SHA256. To fix, you can upgrade lockfile:

npx nuxi@latest upgrade --force

@WamiqM With your reproduction, there is another edge case BTW that is different from hash collision. Since now key is based on static code location of useAsyncData, all 3 composables are depending on same key. You need to compute the key by yourself. Otherwise it works but each call updates all 3.

(Docs need to be improved)

Example:

import { hash } from 'ohash'

export const apiFetch = (url: string, fetchOptions: any = {}) => {
  return useFetch(url, {
    baseURL: 'https://api.github.com/',
    key: hash(['api-fetch', url, fetchOptions]), // <---
    ...fetchOptions,
    headers: {
      ...fetchOptions.headers,
    },
  });
};

Note: You can use any custom key instead of hashing input or manually pass as 3rd argument. Hash is just probably safest

Note: For nested fetch composables, I would recommend to switch to useState with explicit key and $fetch.

I also ran into this problem. useFetch seems to be broken in some way. I have code like in this example: https://v3.nuxtjs.org/guide/features/data-fetching/#using-async-setup .

After upgrading to rc. 5 it breaks. The first useFetch runs again on the client and the second useFetch doesn’t run. Rolling back to rc. 4 fixes it.

I have got a similar problem after upgrading from RC. 4 to RC. 5 useFetch runs only for the first request. Subsequent useFetch requests return a copy of the first request’s data.

Following are the reproduction projects for RC. 4 and RC. 5 similar to my current setup.

I tried @pi0, and it didn’t fix the problem. So I just opened a Github issue ^^ Thanks for your help!

Any code snippet of usage could also help in new issue. Can you please also try edge? (https://v3.nuxtjs.org/guide/going-further/edge-channel). We just pushed an improvement regarding key generation.

All right, seems like something is broken in my setup. Closing this for now. Thanks for all the insightful messages!