传递闭包
为了让 Qwik 能够独立地恢复和渲染页面上的每个组件,道具必须是可序列化的。如果我们希望将回调传递给子组件,就会出现问题。回调是函数,函数本身不可直接序列化,但可以通过 $()
将其转换为 QRL 来进行序列化。
QRL
跨可序列化边界的函数传递必须通过 QRL 完成。QRL 是函数的序列化形式。(请参阅高级部分中的 QRL。)
Qwik 提供了以 $
结尾的便捷 API - 它们等效于直接调用 $()
。这两行代码是等效的
- 内联:
useTask$(() => {...}/>
- 显式:
const callbackQrl = $(() => {...}); useTaskQrl(callbackQrl)
大多数情况下,我们使用第一种形式,因为它允许我们将回调直接内联到 API 中。但在某些情况下,需要使用第二种形式,以便将函数声明的位置与使用位置分开。
声明回调道具
组件可以通过以下方式在道具中声明回调:
- 以
$
结尾的属性(如goodbye$
) - 属性的类型为
QRL<T>
,其中T
是 QRL 指向的延迟引用类型(函数签名)。
interface MyComponentProps {
goodbye$: QRL<() => void>;
hello$: QRL<() => void>;
}
export const MyComponent = component$((props: MyComponentProps) => { ... });
这允许 <MyComponent>
的用户使用 goodbye$
形式,如下所示
<MyComponent goodbye$={goodbyeQrl} hello$={() => {...}} />
使用回调道具
请注意,<MyComponent>
组件接收一个回调函数。
将 props.goodbye$
作为引用传递给 <button>
<button onClick$={props.goodbye$}>good bye</button>
为 <button>
创建一个新的回调,并在内部调用回调 QRL。
<button
onClick$={async () => {
await props.hello$?.invoke('World');
}}
>
hello
</button>
这种形式允许 <button>
使用自定义参数调用回调。请注意,调用需要 async
和 await
,因为 QRL 是延迟加载的。