QwikDev / qwik

Instant-loading web apps, without effort
https://qwik.dev
MIT License
20.89k stars 1.32k forks source link

[🐞]Error: Code(13): Actual value for useContext() can not be found... #6399

Open williamsdyyz opened 6 months ago

williamsdyyz commented 6 months ago

Which component is affected?

Qwik Runtime

Describe the bug

Attempting to show a component client side only - no SSR The component calls useLocation Qwik thows an error: Error: Code(13): Actual value for useContext() can not be found, make sure some ancestor component has set a value using useContextProvider()

Reproduction

https://stackblitz.com/edit/qwik-starter-wvympk?file=src%2Froutes%2Findex.tsx

Steps to reproduce

  1. Run npm install && npm run dev
  2. Make sure you can see the console for the running app
  3. Click the "Show Component" button
  4. See error in console

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.20.3 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    @builder.io/qwik: ^1.4.3 => 1.4.3 
    @builder.io/qwik-city: ^1.4.3 => 1.4.3 
    typescript: 5.3.3 => 5.3.3 
    undici: 5.28.2 => 5.28.2 
    vite: 4.5.2 => 4.5.2

Additional Information

The error message seems to indicate that this is expected behavior. I would contend that it's pretty bad behavior if that's the case! I had code that was working perfectly until I introduced a new route that did't call useLocation server-side

DustinJSilk commented 6 months ago

Try changing line 17 to {isShowing.value && <ClientOnlyComponent />}

williamsdyyz commented 6 months ago

Try changing line 17 to {isShowing.value && <ClientOnlyComponent />}

Yes, that will work for sure, but I can already work around the issue. The point is that totally valid code causes the runtime to throw an error and quit.

The Stackblitz project is the simplest form I could find that would reproduce the problem. It's not representative of the code I'm actually trying to write (something similar to the Portals example in the docs)

The bit that's interesting is the code was initially using useComputed:

const Comp = useComputed$(() =>
  isShowing.value ? ClientOnlyComponent : undefined
)
return(
   ....
   {Comp3.value && <Comp3.value />}
   ....
)

Which also didn't work, but this did

const Comp = isShowing.value ? ClientOnlyComponent : undefined;
...
{Comp && <Comp />}

which is why I tried contriving what's in the Stackblitz code

const Comp = isShowing.value ? { value: ClientOnlyComponent } : {}
...
{Comp.value && <Comp.value />}

What's the difference between 2 & 3? Why does having Comp stored in an object propety make a difference?

wmertens commented 5 months ago

qwik only serializes context that is used during SSR. Are you using useLocation anywhere during SSR? If not, add it somewhere.

This is a feature to prevent sending useless context data to the client.

If this was the problem, how should the error message have been changed to make this clear to you?

williamsdyyz commented 5 months ago

In newer versions of Qwik, the error message has been improved with the additon of "In the browser make sure that the context was used during SSR so its state was serialized." so that makes it clearer what the issue is.

However there are a few remaining concerns:

  1. Maybe I'm not understanding, but if there are multiple SSR entrypoints with no common ancestor, you would have to add use to every entrypoint? And remember to do that every time you use a new context? And rememer to copy/paste all the use calls to a new entrypoint when you create it?
  2. What if the context is only relevant for a CSR-only part of the code - such as a store containing state?
  3. Why in the examples above (and on Stackblitz) does {Comp.value && <Comp.value />} work when the others thow the error?