最佳实践

在模板中使用内联操作

如果操作在模板中进行内联,Qwik 优化器可以更好地优化应用的响应性。

次优实现
// 不要这样做!
export default component$(() => {
  const signal = useSignal(0);
  const isBiggerThanZero = signal.value > 0 ? 'Bigger than zero' : 'Smaller than zero';
  return (
    <div>
      <button onClick$={() => signal.value++}>+</button>
      <button onClick$={() => signal.value--}>-</button>
      <div>{isBiggerThanZero} - Current value: { signal.value }</div>
    </div>
  );
});

上述实现会导致整个模板在信号变化时重新渲染。这是因为 isBiggerThanZero 没有在模板中进行内联。

最佳实现
export default component$(() => {
  const signal = useSignal(0);
  return (
    <div>
      <button onClick$={() => signal.value++}>+</button>
        <button onClick$={() => signal.value--}>-</button>
        <div>
          {signal.value > 0 ? 'Bigger than zero' : 'Smaller than zero'} - Current
          value: {signal.value}
        </div>
    </div>
  );
});

避免在 useVisibleTask$() 中注册 DOM 事件

Qwik 允许以声明式方式注册事件监听器,可以使用 useOn() 或者使用 JSX。

当使用 useVisibleTask 来以编程方式注册事件时,即使事件未触发,我们也会急切地下载和执行 JavaScript。

次优实现
// 不要这样做!
useVisibleTask$(({ cleanup }) => {
  const listener = (event) => {
    const mouseEvent = event as MouseEvent;
    console.log(mouseEvent.x, mouseEvent.y);
  };
  document.addEventListener('mousemove', listener);
 
  cleanup(() => {
    document.removeEventListener('mousemove', listener);
  });
});

上述实现会导致更多的 JavaScript 急切加载,而不是精确响应用户事件。前端 JavaScript 加载增加会导致应用性能变慢。

相反,使用 useOnDocument() 钩子在 document 对象上注册事件,这样 Qwik 就不会在事件触发之前执行任何 JavaScript。

最佳实现
useOnDocument(
  'mousemove',
  $((event) => {
    const mouseEvent = event as MouseEvent;
    console.log(mouseEvent.x, mouseEvent.y);
    // 不需要手动清理!
  })
);

如果不确定时,可以使用以下替代 useVisibleTask$() 的方法:

  • useOn(): 在 当前组件的根元素 上监听事件。
  • useOnWindow(): 在 window 对象上监听事件。
  • useOnDocument(): 在 document 对象上监听事件。

避免直接从 window 对象访问 location

不要直接访问 window.location,而是使用 useLocation() 钩子。

次优实现
// 不要这样做!
useVisibleTask$(()=> {
    if (window.location.href).includes('foo') {
        //... 做某事
    }
})
// 或者
if (typeof window !== "undefined") {
    const queryParams = new URLSearchParams(window.location.search);
    const query: Record<string, string> = {};
    queryParams.forEach((value, key) => {
        query[key] = value;
    })
    doTheThing(query);
}

许多与位置信息相关的操作可以在初始服务器端渲染期间执行,生成纯 HTML,没有任何 JavaScript 开销。

通过强制将此逻辑在客户端上运行,会引入更多的前端 JavaScript 加载,并导致急切加载。

使用 if typeof window !== "undefined" 模式可能会导致代码被跳过。在服务器端,由于 window 总是 undefined,代码块将被跳过。

虽然开发人员可能习惯于代码运行两次,但 Qwik 通过提供更高效的方法来消除这种必要性。

最佳实现
// 这样做!
const location = useLocation();
 
if (location.url.href.includes('foo')) {
  // 做某事
}
 
doTheThing(location.url.searchParams);

异常情况

当使用 SSG 仅用于纯静态文件时,在构建时无法依赖服务器获取当前位置信息。

然而,要小心!如果所需信息(如查询参数)直到用户事件发生时才需要,将检查包含在事件处理代码中。

这种方法有助于防止 JavaScript 的急切加载,提高性能。

参考:useLocation() 文档

Contributors

Thanks to all the contributors who have helped make this documentation better!

  • mhevery
  • the-r3aper7
  • manucorporat
  • jakovljevic-mladen
  • kerbelp
  • wfairclough
  • cunzaizhuyi
  • reemardelarosa
  • un33k
  • egmaleta
  • mugan86
  • hamatoyogi