question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

useState() after async causes nuxt instance unavailable

See original GitHub issue

Environment


  • Operating System: Linux
  • Node Version: v14.18.1
  • Nuxt Version: 3.0.0-27304790.cad09fe
  • Package Manager: yarn@1.22.17
  • Bundler: Vite
  • User Config: -
  • Runtime Modules: -
  • Build Modules: -

Reproduction

https://codesandbox.io/s/focused-forest-8brjk?file=/app.vue

Describe the bug

Calling useState() after an async call in the setup method causes the following error to throw:

Error: nuxt instance unavailable
    at Module.useNuxtApp (file:///sandbox/.nuxt/dist/server/server.mjs:244:13)
    at Module.useState (file:///sandbox/.nuxt/dist/server/server.mjs:660:38)
    at Module.useCounter (file:///sandbox/.nuxt/dist/server/server.mjs:1901:41)
    at setup (file:///sandbox/.nuxt/dist/server/server.mjs:1849:60)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)

However, if the useState() is moved to before the async call, no error is thrown.

Additional context

No response

Logs

No response

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
danielroecommented, Dec 4, 2021

You’re right that composables do enable you to decouple logic and make it reusable. But what most people mean by composables are effectively setup functions that have to be run in setup(). They do whatever you need to ‘set up’ your functionality, and then return functions/state/etc.

So you can’t just run those setup functions at any time - they almost always need to be run within the setup function to close over whatever key instances or values you can access there.

For example, to refactor your composable:

// composables/useLocalUser.ts

import { useState } from '#app'

export default function useLocalUser() {
  const state = useState<{id: string}>('localUser', () => {id: null})
  function setLocalUser(user: { id: string }) {
    state.value = { id: user.id }
  }

  return {
    state,
    setLocalUser
  }
}

// composables/useFetchRemoteUser.ts

import useLocalUser from '~/composables/useLocalUser'

export default function useFetchRemoteUser() {
+ const { setLocalUser } = useLocalUser()  // Will fail with the `nuxt instance unavailable` error
  async function fetch(id: string): Promise<{ id: string } | null> {
    const result = await fetchFromAPI(id)

-   const { setLocalUser } = useLocalUser()  // Will fail with the `nuxt instance unavailable` error
    setLocalUser(result.user)
  
    return result.user
  }

  return {
    fetch
  }
}
2reactions
coryvirokcommented, Dec 3, 2021

FWIW and for anyone else who comes across this, I ended up moving all of my composables into Pinia datastores. I’m not sure if the same issue occurs with Pinia, but I haven’t ran into it yet. And not having to worry about what happens before vs after async is pretty important for me to keep my codebase maintainable.

For whoever might be following along, I think there’s an opportunity for Vue/Nuxt folks to better describe the intended use cases for composables. I thought it was to decouple logic and make it reusable in any part of your codebase, (e.g. templates, setup, router guards, plugins.) But from what I gather, this isn’t entirely true. So, some guidance on what’s kosher in the way of examples would be tremendously helpful.

Normally, I’d offer to help write the docs/examples. But I feel pretty far out of my depth on this topic.

Read more comments on GitHub >

github_iconTop Results From Across the Web

using try/catch with an async method inside a middleware ...
I'm trying to write an async middleware. However, when catching the rejected promise an error is thrown by nuxt when using navigateTo() :....
Read more >
The useState set method is not reflecting a change immediately
If async was the only reason, it would be possible to await setState() . However, both props and state are assumed to be...
Read more >
`useEffect()` and `async` - DEV Community ‍ ‍
setState() [from inside componentDidMount()]; render(). Even though there is a second render, the React Docs state that the user will not see ...
Read more >
Using Async Await Inside React's useEffect() Hook
After the component mounts, we let a useEffect hook spin off a quick fetchUsers() call which returns us a Promise type, which we...
Read more >
Hooks FAQ - React
Mutating state in place and calling setState will not cause a re-render. Try to avoid this pattern if possible.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found