ベストプラクティス

テンプレート内のインライン操作

操作がテンプレートにインライン化されている場合、Qwikオプティマイザーはアプリケーションのリアクティビティをより最適化できます。

最適ではない実装
// Don't do this!
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>
  );
});

シグナルの読み取りを `useTask$` または `useComputed$` に移動する

これは上記のヒントに似ています。

Qwikがシグナル/ストア値を「読み取る」たびに、「読み取り」が行われている関数は、そのシグナルの変更ごとに再実行されます。

そのため、可能な限り、コンポーネント関数内ではなく、 `useTask$` または `useComputed$` 関数内で値を「読み取る」(そして追跡する)方が良いでしょう。

そうでない場合、コンポーネント関数は変更ごとに再実行されます。

最適ではない実装
// Don't do this!
export default component$(() => {
  const count = useSignal(1);
  const doubleCount = count.value*2;
  return (
    <div>{doubleCount}</div>
  );
});

上記の実装では、シグナルが変更されるとテンプレート全体が再レンダリングされます。

以下では、 `count.value` が変更された場合、 `useComputed$` 関数のみが再実行されます。

最適な実装
export default component$(() => {
  const count = useSignal(1);
  const dobuleCount = useComputed$(() => count.value*2);
  return (
    <div>{doubleCount.value}</div>
  );
});

`useVisibleTask$()` は最後の手段として使用する

便利な反面、`useVisibleTask$()` はコードを積極的に実行し、メインスレッドをブロックするため、タスクが完了するまでユーザーインタラクションができません。これは、緊急脱出手段と考えることができます。

不明な場合は、 "useVisibleTask$()" の代わりに以下を使用してください。

  • `useTask$()` -> SSRモードでコードを実行します。
  • `useOn()` -> `現在のコンポーネント` のルート要素でイベントをリッスンします。
  • `useOnWindow()` -> `window` オブジェクトでイベントをリッスンします。
  • `useOnDocument()` -> `document` オブジェクトでイベントをリッスンします。

ただし、結果を達成する唯一の方法である場合があります。

その場合は、 "useVisibleTask$" の前の行に `// eslint-disable-next-line qwik/no-use-visible-task` を追加して警告を削除できます。

`useOn()`、 `useOnWindow()`、または `useOnDocument()` でDOMイベントを登録する

Qwikでは、 `useOn()` またはJSXを使用して、宣言的な方法でイベントリスナーを登録できます。

`useVisibleTask$()` を使用してプログラムでイベントを登録する場合、イベントがトリガーされない場合でも、JavaScriptを積極的にダウンロードして実行しています。

最適ではない実装
// Don't do this!
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はイベントがトリガーされるまでJSを実行しません。

最適な実装
useOnDocument(
  'mousemove',
  $((event) => {
    const mouseEvent = event as MouseEvent;
    console.log(mouseEvent.x, mouseEvent.y);
    // No manual clean up required!
  })
);

`window` オブジェクトからロケーションにアクセスしない

`window.location` に直接アクセスしないでください。代わりに `useLocation()` フックを使用してください。

最適ではない実装
// Don't do this!
useVisibleTask$(()=> {
    if (window.location.href).includes('foo') {
        //... do the thing
    }
})
// or
useTask$(() => {
  if (isBrowser) {
        if (window.location.href).includes('foo') {
        //... do the thing
    }
  }
})

ロケーション情報に関連する多くのアクションは、初期サーバーサイドレンダリング中に実行できるため、JavaScriptのオーバーヘッドなしで純粋なHTMLが生成されます。

このロジックをクライアントサイドで強制的に実行すると、初期JavaScriptが増加し、積極的な読み込みが発生します。

最適な実装
// Do this!
const location = useLocation();
 
if (location.url.href.includes('foo')) {
  // Do the thing
}

例外

純粋に静的なファイルにSSGを使用する場合、ビルド時に現在のロケーション情報がないサーバーに依存することは避けられません。

ただし、注意が必要です。必要な情報(クエリパラメータなど)がユーザーイベントが発生するまで必要ない場合は、イベントハンドリングコード内にチェックを組み込んでください。

このアプローチは、JavaScriptの積極的な読み込みを防ぎ、パフォーマンスを向上させるのに役立ちます。

参照:useLocation() ドキュメント

貢献者

このドキュメントの改善に貢献してくれたすべての貢献者に感謝します!

  • mhevery
  • the-r3aper7
  • manucorporat
  • jakovljevic-mladen
  • kerbelp
  • wfairclough
  • cunzaizhuyi
  • reemardelarosa
  • un33k
  • egmaleta
  • mugan86
  • octoper
  • mrhoodz
  • VinuB-Dev
  • anartzdev
  • adamdbradley
  • hamatoyogi
  • maiieul