qwik api介绍
| 类别 | 名称 | 功能描述 | 适用场景 |
|---|---|---|---|
| 生命周期 | onMount | 组件挂载时执行 | 初始化DOM操作、设置事件监听 |
| onUnmount | 组件卸载时执行 | 清理资源、移除事件监听 | |
| onVisible | 组件在视口可见时执行 | 懒加载内容、分析追踪 | |
| onResume | 从序列化状态恢复时执行 | 恢复应用状态 | |
| 核心API | component$ | 创建Qwik组件 | 定义可序列化组件 |
| $ | 将函数序列化 | 事件处理、延迟加载函数 | |
| useClientMount$ | 客户端挂载时执行 | 需要DOM的操作 | |
| useServerMount$ | 仅在服务器执行 | 数据获取、SEO优化 | |
| useStore | 创建响应式状态对象 | 状态管理 | |
| useSignal | 创建信号(单一值响应式) | 简单状态管理 | |
| useTask$ | 响应状态变化的副作用 | 数据同步、计算派生状态 | |
| useResource$ | 异步资源管理 | 数据获取、异步操作 | |
| 路由API | routeLoader$ | 路由加载器 | 服务端数据获取 |
| routeAction$ | 路由动作 | 表单处理、数据修改 | |
| routeResolve$ | 路由解析器 | 数据预获取 | |
| useLocation | 获取路由位置信息 | 路由相关逻辑 | |
| 样式API | useStyles$ | 内联样式 | 组件样式封装 |
| useStylesScoped$ | 作用域样式 | 避免样式冲突 | |
| 上下文API | createContextId | 创建上下文ID | 状态共享 |
| useContext | 消费上下文 | 访问共享状态 | |
| useContextProvider | 提供上下文值 | 提供共享状态 | |
| 高级API | useLexicalScope | 访问词法作用域 | 闭包状态访问 |
| useMethod | 优化方法调用 | 组件方法优化 | |
| noSerialize | 阻止序列化 | 非序列化对象处理 | |
| version | 获取Qwik版本 | 调试、兼容性检查 |
一、Qwik生命周期详解
Qwik的生命周期与传统框架有显著不同,其核心理念是"可恢复性"(resumability),而非传统框架的hydration。这使得Qwik应用启动速度极快,即使在低端设备上也能提供出色的性能体验。
1. 应用启动流程
Qwik应用的启动过程分为几个关键阶段:
- 服务端渲染(SSR): 服务器生成HTML和序列化的应用状态
- HTML交付: 完整的HTML发送到客户端
- 可恢复性恢复: 客户端识别已序列化的状态,无需重新执行组件函数
- 事件绑定: 仅在用户交互时,按需加载和执行相关代码
2. 组件生命周期
onMount
组件挂载时触发,但与传统框架不同,Qwik的onMount仅在组件首次变为交互式时执行。
import { component$, useOnMount$ } from '@builder.io/qwik';
export const MyComponent = component$(() => {
useOnMount$(() => {
console.log('组件已挂载并可交互');
// 这里的代码只会在客户端执行
});
return <div>挂载示例</div>;
});
onUnmount
当组件从DOM中移除时触发,用于清理工作。
import { component$, useOnUnmount$ } from '@builder.io/qwik';
export const MyComponent = component$(() => {
useOnUnmount$(() => {
console.log('组件即将卸载');
// 清理定时器、事件监听等
});
return <div>卸载示例</div>;
});
onVisible
Qwik特有的生命周期,当组件进入视口可见区域时触发,用于优化资源加载。
import { component$, useOnVisible$ } from '@builder.io/qwik';
export const LazyComponent = component$(() => {
useOnVisible$(() => {
console.log('组件已进入视口');
// 加载非关键资源
});
return <div>可见性示例</div>;
});
onResume
Qwik特有的生命周期,当应用从序列化状态恢复时触发。
import { component$, useOnResume$ } from '@builder.io/qwik';
export const ResumeComponent = component$(() => {
useOnResume$(() => {
console.log('组件已从序列化状态恢复');
// 恢复交互状态
});
return <div>恢复示例</div>;
});
二、Qwik核心API详解
1. 组件相关API
component$
创建Qwik组件的基础API,使组件可序列化。
import { component$, PropFn } from '@builder.io/qwik';
interface MyComponentProps {
name: string;
onAction$?: PropFn<void>;
}
export const MyComponent = component$<MyComponentProps>((props) => {
return (
<div>
<h1>Hello {props.name}</h1>
<button onClick$={props.onAction$}>点击</button>
</div>
);
});
$
用于将函数标记为可序列化,是Qwik的标志性API。
import { $, component$ } from '@builder.io/qwik';
export const Button = component$(() => {
const handleClick = $(() => {
console.log('按钮被点击');
});
return <button onClick$={handleClick}>点击</button>;
});
2. 状态管理API
useStore
创建一个响应式状态对象,当对象属性更改时自动更新相关组件。
import { component$, useStore } from '@builder.io/qwik';
export const Counter = component$(() => {
const store = useStore({
count: 0,
items: [] as string[],
nested: {
value: 'hello'
}
});
return (
<div>
<p>计数: {store.count}</p>
<button onClick$={() => store.count++}>增加</button>
</div>
);
});
useSignal
创建一个包含单一值的响应式信号,比useStore更轻量。
import { component$, useSignal } from '@builder.io/qwik';
export const Counter = component$(() => {
const count = useSignal(0);
return (
<div>
<p>计数: {count.value}</p>
<button onClick$={() => count.value++}>增加</button>
</div>
);
});
3. 任务与副作用API
useTask$
用于在数据变化时执行副作用,类似于React的useEffect。
import { component$, useTask$, useStore } from '@builder.io/qwik';
export const DataFetcher = component$(() => {
const store = useStore({
userId: 1,
userData: null as any,
loading: false,
});
useTask$(({ track }) => {
// 跟踪store.userId的变化
const userId = track(() => store.userId);
store.loading = true;
// 模拟API调用
fetch(`https://api.example.com/users/${userId}`)
.then(res => res.json())
.then(data => {
store.userData = data;
store.loading = false;
});
});
return (
<div>
<input
type="number"
value={store.userId}
onInput$={(e) => store.userId = +(e.target as HTMLInputElement).value}
/>
{store.loading && <p>加载中...</p>}
{store.userData && <pre>{JSON.stringify(store.userData, null, 2)}</pre>}
</div>
);
});
useResource$
专门用于处理异步资源,提供加载状态管理。
import { component$, useResource$, Resource } from '@builder.io/qwik';
export const UserData = component$(() => {
const userId = useSignal(1);
const userData = useResource$<any>(async ({ signal }) => {
const res = await fetch(`https://api.example.com/users/${userId.value}`, { signal });
return res.json();
});
return (
<div>
<input
type="number"
value={userId.value}
onInput$={(e) => userId.value = +(e.target as HTMLInputElement).value}
/>
<Resource
value={userData}
onPending={() => <p>加载用户数据...</p>}
onResolved={(data) => (
<div>
<h2>{data.name}</h2>
<p>{data.email}</p>
</div>
)}
onRejected={(error) => <p>加载失败: {error.message}</p>}
/>
</div>
);
});
4. 路由相关API
routeLoader$
在路由加载时获取数据,支持服务端和客户端。
import { routeLoader$, type RequestHandler } from '@builder.io/qwik-city';
export const useUserData = routeLoader$<any>(async (requestEvent) => {
const userId = requestEvent.params.userId;
const res = await fetch(`https://api.example.com/users/${userId}`);
return res.json();
});
// 在组件中使用
export default component$(() => {
const userData = useUserData();
return <div>{userData.value?.name}</div>;
});
routeAction$
处理表单提交和其他用户操作。
import { routeAction$, Form, zod$, z } from '@builder.io/qwik-city';
const userSchema = z.object({
name: z.string().min(3),
email: z.string().email()
});
export const useAddUserAction = routeAction$(
async (data, requestEvent) => {
// 服务器端处理逻辑
const response = await fetch('https://api.example.com/users', {
method: 'POST',
body: JSON.stringify(data)
});
return response.json();
},
zod$(userSchema) // 验证
);
export default component$(() => {
const action = useAddUserAction();
return (
<Form action={action}>
<input type="text" name="name" required />
<input type="email" name="email" required />
<button type="submit">添加用户</button>
{action.value?.success && <p>用户添加成功!</p>}
</Form>
);
});
三、Qwik Hooks详解
1. 核心Hooks
useVisibleTask$
在组件进入视口时执行,用于优化资源加载,如懒加载图片、视频等。
import { component$, useVisibleTask$ } from '@builder.io/qwik';
export const LazyImage = component$(({ src, alt }: { src: string; alt: string }) => {
const imageRef = useSignal<Element>();
useVisibleTask$(({ cleanup }) => {
if (imageRef.value) {
const img = new Image();
img.src = src;
img.onload = () => {
if (imageRef.value) {
(imageRef.value as HTMLImageElement).src = src;
}
};
cleanup(() => {
img.onload = null;
});
}
}, { strategy: 'intersection-observer' });
return <img ref={imageRef} alt={alt} data-src={src} />;
});
useStyles$
将CSS样式注入到文档中,支持内联样式。
import { component$, useStyles$ } from '@builder.io/qwik';
export const StyledComponent = component$(() => {
useStyles$(`
.my-component {
padding: 1rem;
border-radius: 8px;
background-color: #f0f0f0;
transition: all 0.3s ease;
}
.my-component:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
`);
return (
<div class="my-component">
<h2>有样式的组件</h2>
<p>这个组件有自己的样式</p>
</div>
);
});
useContext
访问通过上下文提供的值,用于跨组件层级共享状态。
import { component$, createContextId, useContext, useContextProvider, useStore } from '@builder.io/qwik';
// 创建上下文ID
const ThemeContext = createContextId<Theme>('theme-context');
interface Theme {
mode: 'light' | 'dark';
setColorScheme: (mode: 'light' | 'dark') => void;
}
export const ThemeProvider = component$(({ children }) => {
const theme = useStore<Theme>({
mode: 'light',
setColorScheme(mode) {
theme.mode = mode;
document.documentElement.classList.toggle('dark', mode === 'dark');
}
});
// 提供上下文值
useContextProvider(ThemeContext, theme);
return children;
});
export const ThemeToggle = component$(() => {
// 消费上下文
const theme = useContext(ThemeContext);
return (
<button onClick$={() => theme.setColorScheme(theme.mode === 'light' ? 'dark' : 'light')}>
切换到 {theme.mode === 'light' ? '暗色' : '亮色'} 模式
</button>
);
});
useClientEffect$
在客户端执行副作用,类似于React的useEffect,但仅在客户端执行。
import { component$, useClientEffect$, useSignal } from '@builder.io/qwik';
export const WindowSize = component$(() => {
const size = useSignal({ width: 0, height: 0 });
useClientEffect$(() => {
const updateSize = () => {
size.value = {
width: window.innerWidth,
height: window.innerHeight
};
};
window.addEventListener('resize', updateSize);
updateSize(); // 初始化
return () => window.removeEventListener('resize', updateSize);
});
return (
<div>
窗口尺寸: {size.value.width} x {size.value.height}
</div>
);
});
2. 高级Hooks
useLexicalScope
访问函数词法作用域中的变量,解决闭包陷阱问题。
import { component$, useLexicalScope, useTask$ } from '@builder.io/qwik';
export const LexicalScopeExample = component$(() => {
const count = useSignal(0);
useTask$(() => {
// 这里无法直接访问count
// 需要使用useLexicalScope来访问
const [countSignal] = useLexicalScope();
console.log('当前计数:', countSignal.value);
});
return (
<div>
<p>计数: {count.value}</p>
<button onClick$={() => count.value++}>增加</button>
</div>
);
});
useMethod
优化组件方法,减少不必要的重新渲染。
import { component$, useMethod, useStore } from '@builder.io/qwik';
export const MethodComponent = component$(() => {
const state = useStore({
items: [] as string[],
addItem(item: string) {
this.items = [...this.items, item];
}
});
const addItemMethod = useMethod(state.addItem);
return (
<div>
<button onClick$={() => addItemMethod('新项目')}>添加项目</button>
<ul>
{state.items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
});
四、Qwik性能优化策略
Qwik的设计核心是性能,以下是几个关键优化策略:
1. 细粒度代码分割
Qwik自动将应用分割成小块,按需加载,而不是一次性加载整个应用。
2. 可恢复性(Resumability)
不同于传统的hydration,Qwik应用在服务端渲染后,可以直接在客户端恢复交互,无需重新执行组件逻辑。
3. 事件委托优化
Qwik使用单一事件监听器处理所有相同类型的事件,减少内存占用。
4. 延迟加载
通过$函数和可见性任务,Qwik只在需要时加载和执行代码。
五、总结
Qwik是一个革命性的前端框架,通过可恢复性架构解决了传统框架hydration带来的性能瓶颈。其独特的生命周期、API和hooks设计使开发者能够构建超快的Web应用,尤其适合内容丰富、对初始加载性能要求高的应用场景。
掌握Qwik的核心概念——序列化、可恢复性、细粒度懒加载,是充分发挥其性能优势的关键。随着Web应用日益复杂,Qwik的设计理念可能会引领下一代前端框架的发展方向。
如果您觉得这篇文章有帮助,请点个赞吧~
评论
请登录后发表评论
去登录