Context
Qwik 提供了一个 context API,非常类似于 React 的useContext()
函数。
事实上,Qwik 的context API 是向下传递数据的最有效方式,减少开销,生成更少的代码,并允许 Qwik 更重地treeshake未使用的数据。
Qwik 的 context API 由 3 个方法组成,可从 @builder.ioqwik
导入:
createContext(contextName: string): Context
useContextProvider(ctx: Context, value: VALUE): Context
useContext(ctx: Context): VALUE
例子
这个例子由两个组件组成,Parent
和 Child
。父组件创建一些新state并将其赋值给context,允许任何后代组件获取对“state”的引用。
同时,父组件正在渲染 <div>Count: {state.count}<div>
,创建一个响应式订阅,
当 Child 更改 click 处理程序<button onClick ={() => state.count++}>
中的值时将重新渲染:。
import {
component$,
useStore,
useContext,
useContextProvider,
createContext,
} from '@builder.io/qwik';
// Create a new context descriptor
export const MyContext = createContext('my-context');
export const Parent = component$(() => {
// Create some reactive storage
const state = useStore({
count: 0,
});
// Assign value (state) to the context (MyContext)
useContextProvider(MyContext, state);
return (
<>
<Child />
<div>Count: {state.count}</div>
</>
);
});
export const Child = component$(() => {
// Get reference to state using MyContext
const state = useContext(MyContext);
return (
<>
<button onClick$={() => state.count++}>Increment</button>
</>
);
});
让我们深入研究涉及的每个 API:
API
createContext()
此方法采用一个字符串作为参数,该字符串为context提供唯一名称,如果您的应用程序使用许多不同的context或您正在编写组件库, 我们建议遵循避免冲突的命名约定,例如:
export const QwikCityContext = createContext('io.builder.qwik.city');
请注意,createContext()
返回的值不包含任何状态,并且它是immutable的。它仅用于描述context的名称和类型,像一个地址或标识符。
因为它不保存任何状态,所以可以调用它并使其成为单例,导出到某些共享模块中。
useContextProvider()
像所有 use-
方法一样,它只能在 component()
的根层级中调用(不能在分支内部调用)。
此方法由一些更高级别的组件调用,它为context分配(提供)一个值。
提供的值不会在整个渲染树中全局可用,而仅对树中的后代组件可用。
传递给 useContextProvider()
的值可以是任何基本类型、对象(包括来自 useStore)或包含可序列化值的数组。
export const Parent = component$(() => {
const reactiveObject = useStore({
count: 0,
});
useContextProvider(MyContextReactive, reactiveObject);
const plainArray = listOfUSPresidents();
useContextProvider(MyContextArray, plainArray);
const appName = 'My super app';
useContextProvider(MyContextString, appName);
return (
<>
<Children />
</>
);
});
让我们看看 Children
组件如何使用这些值:
useContext()
同样,像所有使用方法一样,它们只能在 component()
的根目录下使用。此方法允许我们将 提供的值 获取到 命名context。
export const Children = component$(() => {
const reactiveObject = useContext(MyContextReactive);
const plainArray = useContext(MyContextArray);
const appName = useContext(MyContextString);
return (
<>
<div>Child components can use any of the provided values, such as {appName}</div>
</>
);
});
Typed contexts
当使用createContext()
创建上下文时,可以提供一个类型。事实上,强烈建议这样做,以减少错误和拼写错误。
export interface SharedState {
count: number;
}
export const MyContext = createContext<SharedState>('my-context');
这样,当在 useContextProvider()
和 useContext()
中使用 MyContext
时,提供的值将具有 SharedState
类型。
看个例子:
import {
component$,
useStore,
useContext,
useContextProvider,
createContext,
} from '@builder.io/qwik';
export interface SharedState {
count: number;
}
export const MyContext = createContext<SharedState>('my-context');
export const Parent = component$(() => {
const state = useStore<SharedState>({
count: 0,
});
useContextProvider(MyContext, state); // type checker will ensure the second param is SharedState
return (
<>
<Child />
<div>Count: {state.count}</div>
</>
);
});
export const Child = component$(() => {
const state = useContext(MyContext); // type of "state" will be `SharedState`
return (
<>
<button onClick$={() => state.count++}>Increment</button>
</>
);
});