QwikDev / qwik

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

Context in Layouts #1648

Closed mastastealth closed 2 years ago

mastastealth commented 2 years ago

Qwik Version

0.10.0

Operating System (or Browser)

W10 / Firefox

Node Version (if applicable)

No response

Which component is affected?

Qwik City

Expected Behaviour

I expected the consumption of a context to work fine within a route given a layout wrapped in a provider.

Actual Behaviour

I get the following error:

Code(13): Actual value for useContext() can not be found, make sure some ancestor component has set a value using useContextProvider()

Additional Information

I've pushed a fresh Qwik City install in an example repo, then applied the simplest version of my context changes, which reproduces the error I'm seeing.

Also worth mentioning, that using that same context from the Header component does work.

nnelgxorz commented 2 years ago

This was implemented previously. Appears to be a regression.

https://github.com/BuilderIO/qwik/issues/599

jrson83 commented 2 years ago

I get the same error when I try to use useContent() inside the default src/root.tsx layout component.

manucorporat commented 2 years ago

I would help a lot of simple piece of code that reproduces it, maybe in the playground https://qwik.builder.io/playground/

nnelgxorz commented 2 years ago

Won't be able to reproduce in the playground because it needs a layout.tsx to trigger the bug.

@mastastealth has the minimal repro here https://github.com/mastastealth/qwik-context/commit/83d16aab40a88365e34e2ca7e030e77938b3c537

The important parts are src/routes/layout.tsx and src/components/my-context.tsx

mastastealth commented 2 years ago

@manucorporat Here's the same repo example code on Stackblitz, if that is quicker.

wmertens commented 2 years ago

FYI I tested with 0.11.1 and 0.0.112 and the issue is still present

NachoVazquez commented 1 year ago

Do we know which version was/will-be released this fix?

wmertens commented 1 year ago

@NachoVazquez should be fixed in 0.12 already I think, can you check with 0.13.3?

mingfang commented 1 year ago

The problem still exist in 0.13.3

NachoVazquez commented 1 year ago

@wmertens Yes, I confirm like @mingfang that the error is still present in 0.13.3

nnelgxorz commented 1 year ago

@mingfang @NachoVazquez Can one of you make a Stackblitz reproduction?

NachoVazquez commented 1 year ago

In a second!

NachoVazquez commented 1 year ago

@nnelgxorz This was created by a coworker of mine. I just updated the versions.

https://stackblitz.com/edit/qwik-starter-vyaj1q?file=src/routes/flower/index.tsx

Steps to reproduce:

  1. Click on the "Blow my mind 🤯 with a context error Code(13)" link.
  2. Check the console.
wmertens commented 1 year ago

@manucorporat confirmed. routes/layout.tsx has the contextprovider, and flower/index.tsx uses the context but has no access to it.

jwickers commented 1 year ago

Still in latest and it only happens when using the Link and doing client-side navigation if that helps.

T-travis commented 1 year ago

After bringing this bug up twice in the Discord server (I'm Data in Discord), I thought I would try to find a workaround for using Link in SPAs.

Steps when using the Stackblitz link:

Context works in Named Layouts always.

https://stackblitz.com/edit/qwik-starter-5xnz1q?file=src/routes/index.tsx

The workaround appears to be to use Named Layouts for now. Hope this helps!

Dindaleon commented 1 year ago

Is this bug still present? Because I am having it right now on version 0.16.2

Dindaleon commented 1 year ago

I found a temporal fix:

Write a component with the following:

import {
  component$,
  Slot,
  useClientEffect$,
  useContext,
} from '@builder.io/qwik'
import { AuthContext } from './authProvider'

export const ContextSetter = component$(() => {
  const auth = useContext(AuthContext)
  useClientEffect$(({ track }) => {
    track(auth)
  })

  return <Slot></Slot>
})

In root.tsx put the component inside the body tags

<body lang="en">
  <ContextSetter>
    <RouterOutlet />
    <ServiceWorkerRegister />
  </ContextSetter>
</body>

It works like a charm. Waiting for an official fix :)

frankroc2022 commented 1 year ago

Bug is still present. And temporal fix not work. Ok, from parent to child it works (without the temporal fix). But not from child to parent. Or how I have to pass data from child to parent. Or what is the correct way to handle this: User input from component a is imported in component c. User input is processed in component b and is imported in the layout.tsx.

imMadsen commented 7 months ago

I know this issue is closed but if someone comes across it. The issue seems to be able to be resolved my using the 'useContextProvider' in Layout instead of having a component that wraps around.

Like if you had 'MyContextProvider' and used it in your layout.tsx

layout.tsx

<MyContextProvider>
</MyContextProvider>
imMadsen commented 7 months ago

Okay, I think I might have a good solution!

Instead of wrapping your component in a provider, simply create provider hook. Here is an example from my project

EnvironmentContext.tsx

export function useEnvironmentProvider() {
    const environment = useStore<EnvironmentContext>({
        state: "Loading",
        registrants: {}
    });

    // eslint-disable-next-line qwik/no-use-visible-task
    useVisibleTask$(() => {
        async function getRegistrants() {
        try {
            const snapshot = await getDocs(collection(db, "registrants"));

            for (const doc of snapshot.docs) {
            environment.registrants[doc.id] = doc.data() as Registrant;
            }

            environment.state = "Valid"
        } catch (e) {
            environment.state = "Invalid";
        }
        }

        getRegistrants();
    });

    useContextProvider(EnvironmentContext, environment)
}

Layout.tsx

export default component$(() => {
  useEnvironmentProvider()

  return (...);
})