乐闻世界logo
搜索文章和话题

Qwik 中的 `$` 符号有什么作用?

2月21日 15:18

Qwik 的 $ 符号是其架构的核心,它不仅仅是一个命名约定,而是编译器处理代码的重要标识。理解 $ 符号的作用对于掌握 Qwik 至关重要。

1. $ 符号的核心作用

$ 符号告诉 Qwik 编译器这是一个需要特殊处理的函数或组件,编译器会对其进行代码分割、序列化和懒加载处理。

2. $ 符号的使用场景

component$ - 组件定义

tsx
import { component$ } from '@builder.io/qwik'; export const MyComponent = component$(() => { return <div>Hello Qwik</div>; });

作用

  • 标识这是一个 Qwik 组件
  • 编译器会自动将组件代码分割成独立的 chunk
  • 组件默认是懒加载的

useSignal / useStore - 状态管理

tsx
import { useSignal, useStore } from '@builder.io/qwik'; export const Counter = component$(() => { const count = useSignal(0); // 不需要 $ const user = useStore({ // 不需要 $ name: 'John', age: 30 }); return <div>{count.value}</div>; });

注意useSignaluseStore 本身不需要 $,但它们创建的状态对象会被编译器特殊处理。

onClick$ / onInput$ - 事件处理

tsx
export const Button = component$(() => { const handleClick$ = () => { console.log('Clicked!'); }; return <button onClick$={handleClick$}>Click me</button>; });

作用

  • 标识这是一个可恢复的事件处理函数
  • 编译器会将事件处理函数独立分割
  • 只在用户触发事件时才加载和执行

useTask$ / useVisibleTask$ - 生命周期

tsx
export const DataComponent = component$(() => { useTask$(() => { console.log('Component mounted or updated'); }); useVisibleTask$(() => { console.log('Component is visible'); }); return <div>Data Component</div>; });

作用

  • 标识这是一个生命周期钩子
  • useTask$ 在服务器和客户端都会执行
  • useVisibleTask$ 只在客户端执行

useResource$ - 异步数据

tsx
export const UserList = component$(() => { const users = useResource$(({ track }) => { track(() => /* 依赖项 */); return fetch('https://api.example.com/users'); }); return ( <div> {users.value?.map(user => <div key={user.id}>{user.name}</div>)} </div> ); });

作用

  • 标识这是一个异步数据获取函数
  • 编译器会处理加载状态和错误状态
  • 支持依赖追踪和重新获取

action$ - 服务端操作

tsx
import { action$ } from '@builder.io/qwik-city'; export const useSubmitForm = action$(async (data, { requestEvent }) => { // 服务端逻辑 return { success: true }; });

作用

  • 标识这是一个服务端操作
  • 编译器会自动处理表单提交和响应
  • 支持类型安全的数据验证

3. $ 符号的编译器处理

代码分割

编译器会自动将带有 $ 的函数分割成独立的文件:

tsx
// 原始代码 export const App = component$(() => { const handleClick$ = () => { console.log('Clicked'); }; return <button onClick$={handleClick$}>Click</button>; }); // 编译后的结构 // App.js - 组件代码 // handleClick.js - 事件处理函数(独立文件)

序列化

编译器会将函数引用序列化到 HTML 中:

html
<!-- 编译后的 HTML --> <button data-qwik="..." onClick$="./handleClick.js#handleClick" > Click </button>

懒加载

编译器会生成懒加载逻辑,只在需要时加载代码:

javascript
// 自动生成的懒加载代码 function loadHandler() { return import('./handleClick.js').then(m => m.handleClick); }

4. $ 符号的命名约定

组件名称

tsx
// 推荐 export const MyComponent = component$(() => {}); // 不推荐(但有效) export const myComponent = component$(() => {});

事件处理函数

tsx
// 推荐 const handleClick$ = () => {}; const handleSubmit$ = () => {}; // 不推荐(但有效) const handle_click$ = () => {}; const clickHandler$ = () => {};

生命周期函数

tsx
// 推荐 useTask$(() => {}); useVisibleTask$(() => {}); // 这些是内置函数,不需要自定义命名

5. 常见错误和注意事项

忘记使用 $

tsx
// 错误:事件处理函数没有使用 $ export const Button = component$(() => { const handleClick = () => { // 缺少 $ console.log('Clicked'); }; return <button onClick={handleClick}>Click</button>; // 错误 }); // 正确 export const Button = component$(() => { const handleClick$ = () => { // 使用 $ console.log('Clicked'); }; return <button onClick$={handleClick$}>Click</button>; // 正确 });

混淆 $ 的使用位置

tsx
// 错误:在 JSX 属性中错误使用 $ export const Button = component$(() => { return <button onClick$={() => console.log('Clicked')}>Click</button>; // 内联箭头函数不应该使用 $ }); // 正确 export const Button = component$(() => { const handleClick$ = () => { console.log('Clicked'); }; return <button onClick$={handleClick$}>Click</button>; });

6. $ 符号的底层原理

编译时转换

Qwik 编译器在编译时会:

  1. 识别所有带有 $ 的函数
  2. 将这些函数提取到独立文件
  3. 生成序列化元数据
  4. 创建懒加载逻辑
  5. 更新函数引用

运行时恢复

在运行时,Qwik 会:

  1. 从 HTML 中读取序列化元数据
  2. 按需加载对应的 JavaScript 文件
  3. 恢复函数的执行上下文
  4. 执行函数逻辑

总结:$ 符号是 Qwik 架构的核心,它通过编译时优化实现了自动的代码分割、序列化和懒加载。理解 $ 符号的作用对于编写高性能的 Qwik 应用至关重要。

标签:Qwik