0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

もう querySelector に頼らない!Svelte開発を支える bind:this

Posted at

はじめに

Svelte を使っていて、ボタンを押したときにinputをフォーカスしたり、スクロールさせたり、サイズを測ったりしたくなったことはありませんか?
Svelte はリアクティブな記述が魅力ですが、ときには DOM ノード(HTML 要素)に直接アクセスしたい場面も出てきます。
そんなときに登場するのが、bind:this構文です。

参考にしたドキュメント

bind:this とは?

bind:thisは、DOM 要素やコンポーネントの参照を取得するための Svelte 独自構文です。

<script>
  let inputEl;

  function focusInput() {
    inputEl.focus(); // DOMノードにアクセス!
  }
</script>

<input bind:this={inputEl} />
<button on:click={focusInput}>フォーカスする</button>

このように書くと、inputEl という変数に 要素の参照(DOM ノード)が代入されます。
これにより、JavaScript の通常の DOM 操作(例:focus() や scrollTop)が可能になります。

どうして bind:this が必要なの?

実際には以下のようなニーズもあります

  • 初期フォーカスを当てたい
  • 要素のスクロール位置を制御したい
  • サイズや位置を測定したい

❌ bind:this を使わなかった場合(非推奨例)

<script>
  function focusInput() {
    document.querySelector('input').focus();
  }
</script>

<input />
<button on:click={focusInput}>フォーカスする</button>

問題点

  • document.querySelector()はグローバルな DOM を検索するため、コンポーネントが複数あった場合に意図しない要素を取得する可能性があります
  • DOM の存在を前提としたコードになるため、SSR(サーバーサイドレンダリング)時にクラッシュするリスクがあります(参考ドキュメント)
  • Svelteのコンポーネントスコープ外の操作になるため、保守性・再利用性が下がる

✅ bind:this を使えば?

<script>
  let inputEl;

  function focusInput() {
    inputEl.focus();
  }
</script>

<input bind:this={inputEl} />
<button on:click={focusInput}>フォーカスする</button>
  • 対象の DOM 要素にだけアクセスできる
  • マウント後に値が代入されるため、タイミングが明確
  • コンポーネントスコープ内の操作なので保守性が高い

よくある使い方

初期フォーカス

<script>
  import { onMount } from 'svelte';
  let input;

  onMount(() => {
    input.focus();
  });
</script>

<input bind:this={input} />

スクロール制御

<script>
  let container;

  function scrollToBottom() {
    container.scrollTop = container.scrollHeight;
  }
</script>

<button on:click={scrollToBottom}>一番下へ</button>

<div bind:this={container} style="height: 100px; overflow: auto;">
  <p>たくさんのテキスト...</p>
</div>


コンポーネントにも使える

<!-- MyComponent.svelte -->
<script>
  export function sayHello() {
    alert('こんにちは!');
  }
</script>
<!-- Parent.svelte -->
<script>
  import MyComponent from './MyComponent.svelte';
  let myComp;

  function callChildMethod() {
    myComp.sayHello(); // 子コンポーネントの関数を呼び出す
  }
</script>

<MyComponent bind:this={myComp} />
<button on:click={callChildMethod}>子の関数を実行</button>

注意点

  • bind:this は 初期レンダリング後に値がセットされるため、使うタイミングに注意(onMount()内で使うのが安全)
  • コンポーネント参照と DOM ノード参照は 異なる型なので、用途に応じて適切に使い分ける
  • TypeScript を使う場合は、HTMLElement 型やコンポーネント型の明示が必要

おわりに

bind:thisは、Svelte の宣言的なスタイルを崩すことなく、必要な場面で DOM 要素やコンポーネントインスタンスに安全にアクセスできる、非常に便利な機能です。
普段はリアクティブな記述で完結できる Svelte ですが、どうしても imperative(命令的)な処理が必要になる場面は出てきます。そんなときでも bind:this を使えば、Svelte の設計思想を尊重しながら柔軟な実装が可能になります。
「いつ、なぜ使うのか」「使わなかった場合にどうなるか」をしっかり理解しておくことで、より保守性が高く、バグの少ないコードを書くことができます。特にコンポーネントの再利用や SSR を考慮するプロジェクトでは、その恩恵を実感できるでしょう。
最後までご覧いただきありがとうございました!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?