Context
Qwik provides a context API, which solves the problem of props drilling and it is very similar to React's functional useContext()
. In fact, Qwik's context API is the most efficient way to pass down the data to different components, reducing overhead, generating less code, and allowing Qwik to treeshake unused data more heavily.
Qwik's context API is made of 3 methods, importable from @builder.io/qwik
:
createContextId(contextName: string): ContextId
useContextProvider(ctx: ContextId, value: VALUE): void
useContext(ctx: ContextId): VALUE
import { type Signal, component$, useSignal } from '@builder.io/qwik';
import {
useContext,
useContextProvider,
createContextId,
} from '@builder.io/qwik';
export const ThemeContext = createContextId<Signal<string>>(
'docs.theme-context'
);
export default component$(() => {
const theme = useSignal('dark');
useContextProvider(ThemeContext, theme);
return (
<>
<button
onClick$={() =>
(theme.value = theme.value == 'dark' ? 'light' : 'dark')
}
>
Flip
</button>
<Child />
</>
);
});
const Child = component$(() => {
const theme = useContext(ThemeContext);
return <div>Theme is {theme.value}</div>;
});
In the above example, we are creating a ContextId
with the name docs.theme-context
and then using it to provide a useSignal
to the default
component. The Child
component is then using the useContext
method to get the useSignal
and render its value.
createContextId()
This method is used to create a new ContextId
.
export interface GenericType {
...
}
export const QwikCityContext = createContextId<GenericType>(name: string): ContextId<GenericType>;
Parameters
name
: it is a unique string given tocreateContextId
as an identifier of context. This will avoid conflicts when there are multiple contexts. It is advised to use a naming convention likeio.builder.qwik.city
.
Returns
Notice that the value returned by createContextId()
does not hold any state, it is an immutable ID object i.e. { id: 'io.builder.qwik.city' }
. It's only used to describe the name and type of the context, like an address or an identifier.
Since it does not hold any state, it's ok to call it and make it a singleton, and export it in some shared module.
useContextProvider()
This method is used to create a Context for a specific component and its descendants, using the ContextId
as the key identifier of the context.
import { component$, useStore, useContextProvider } from '@builder.io/qwik';
export const Parent = component$(() => {
const qwikCityObject = useStore<GenericType>({
...
});
useContextProvider(QwikCityContext, qwikCityObject);
useContextProvider(PlainArrayContext, [1, 2, 3])
useContextProvider(AppNameContext, "My Qwik App")
return (
<Children />
);
});
Parameters
-
ContextId
: A previously created Context must be supplied which will serve as an identifier for the data being provided (second parameter). -
data
: you can provide any data type like Qwik's useSignal, useStore, Array, Objects.
Caveats
- The provided value will not be globally available across the whole render tree, but only to descendant components in the tree.
useContext()
This method is used to get the value of Context
which is provided by Parent Component.
import { component$, useContext } from '@builder.io/qwik';
export const Children = component$(() => {
const qwikCityObject = useContext(QwikCityContext);
const plainArray = useContext(PlainArrayContext);
const appName = useContext(AppNameContext);
return (
<div>Child components can use any of the provided values, such as {appName}</div>
);
});