✍️

Svelteで手軽にTextareaの自動リサイズを実装する

2024/06/20に公開

はじめに

この記事では、Svelteのuseディレクティブとjackmoore/autosizeを利用して、Textareaの自動リサイズ機能を手軽に実装する方法を紹介します。また、他のフレームワーク(React)と比較して、Svelteのシンプルについても触れています。

jackmoore/autosizeは、Textarea要素に自動リサイズ機能を追加するための軽量なライブラリです。ユーザーが入力するテキストの量に応じて、Textareaの高さを自動的に調整することができます。

https://github.com/jackmoore/autosize

Reactでの実装方法

最初にReactでの実装を見てみます。

Reactで複数のTextareaを用意して自動リサイズを実装する場合、各Textareaに対してrefを使用してDOM要素にアクセスし、ライブラリを適用する必要があります。

import { useRef, useEffect } from 'react';
import autosize from 'autosize';

export const Component = () => {
  const textareaRefs = useRef([]);

  useEffect(() => {
    textareaRefs.current.forEach(textarea => {
      if (textarea) {
        autosize(textarea);
      }
    });
  }, []);

  return (
    <div>
      <textarea ref={el => textareaRefs.current[0] = el}></textarea>
      <textarea ref={el => textareaRefs.current[1] = el}></textarea>
      <textarea ref={el => textareaRefs.current[2] = el}></textarea>
    </div>
  );
};

この方法では、各Textareaに対して個別にrefを設定して配列を管理する必要があり、少しコードが冗長になります。
これらの問題を解決するために、texareaをラップしたTextareaコンポーネントを作成することで、refの管理をコンポーネント内にカプセル化します。

import { useRef, useEffect } from 'react';
import autosize from 'autosize';

export const Textarea = ({ autoResize, ...props }) => {
  const textareaRef = useRef(null);

  useEffect(() => {
    if (autoResize && textareaRef.current) {
      autosize(textareaRef.current);
    }
  }, [autoResize]);

  return <textarea ref={textareaRef} {...props}></textarea>;
};

このコンポーネントを使用することで、ref管理が不要になりコードがシンプルになりました。

import Textarea from './Textarea';

export const Component = () => {
  return (
    <div>
      <Textarea autoResize={true} />
      <Textarea autoResize={true} />
      <Textarea autoResize={true} />
    </div>
  );
};

しかし、最終的にはTextareaコンポーネントを作成する必要があり、コンポーネントの管理コストが増えてしまいます。特に小規模なプロジェクトや簡単な実装を行いたい場合には、Reactでの実装は少し煩雑に感じるかもしれません。

次に、Svelteでの実装方法を見ていきます。

Svelteのuseディレクティブの紹介

実装例を示す前に、Svelteのuseディレクティブについて紹介します。

useディレクティブとは?

Svelteのuseディレクティブは、DOM要素にカスタムアクションを適用するための仕組みです。

Web開発では、特定のDOM要素に対して特定の機能を追加したい場合があります。例えば、入力フィールドにフォーカスが当たったときに特定のスタイルを適用したり、外部のライブラリを使って特定の動作を実装したりすることが考えられます。Svelteのuseディレクティブを使うと、これらの操作を簡単に行うことができます。

useディレクティブを使わない場合、DOM要素に対する操作は、Svelteのライフサイクルメソッド(例えば、onMount)を使って行います。しかし、useディレクティブを使うと、DOM要素の操作を再利用可能なアクションとしてカプセル化でき、コードの再利用性と可読性が向上します。

カスタムアクションとは?

カスタムアクションは、Svelteのuseディレクティブを使ってDOM要素に特定の振る舞いを追加するためのJavaScript関数です。アクションは、DOM要素が挿入されたとき、更新されたとき、および削除されたときに特定の処理を実行するための構造を持っています。

export function myAction(node) {
  // 初期化処理
  // 例: node.style.color = 'red';

  return {
    update(newParameters) {
      // 更新処理
      // 例: node.style.color = newParameters.color;
    },
    destroy() {
      // クリーンアップ処理
      // 例: node.style.color = '';
    }
  };
}
  • node:アクションが適用されるDOM要素です。例えば、特定のHTML要素(<div>, <input>など)です。
  • update:アクションが更新されたときに呼び出されます。新しいパラメータが渡されます。この関数は省略可能です。
  • destroy:DOM要素が削除されたときに呼び出され、クリーンアップ処理を行います。この関数も省略可能です。

useディレクティブの利用例

以下は、簡単なuseディレクティブの利用例です。

<script>
  // テキストの色を保持する変数
  let textColor = 'red';

  // カスタムアクションを定義
  export function setColor(node, color) {
    node.style.color = color;

    return {
      update(newColor) {
        node.style.color = newColor;
      },
      destroy() {
        node.style.color = null;
      }
    };
  }
</script>

<style>
  input {
    margin-bottom: 10px;
    padding: 5px;
    font-size: 1rem;
  }
</style>

<!-- ユーザーが色を入力するためのテキストボックス -->
<input type="text" bind:value={textColor} placeholder="Enter a color" />

<!-- カスタムアクションを適用したテキスト -->
<p use:setColor={textColor}>このテキストの色は変わります。</p>

この例では、setColorというカスタムアクションを定義し、<p>要素に適用しています。nodeは対象のDOM要素を指し、update関数はカスタムアクションが更新されたときに呼び出され、destroy関数は要素が削除されたときに呼び出されます。

このように、useディレクティブとカスタムアクションを使うことで、DOM要素に対して簡潔かつ再利用可能な形で操作を適用することができます。

Svelteでの実装方法

autosizeアクションの作成

まず、Textareaの自動リサイズ機能を実装するためのカスタムアクションを作成します。

import $autosize from 'autosize';

export const autosize = (node) => {
  $autosize(node);

  return {
    update() {
      $autosize.update(node);
    },
    destroy() {
      $autosize.destroy(node);
    }
  };
};

Svelteコンポーネントでの使用

次に、作成したカスタムアクションを使用して、複数のTextarea要素に自動リサイズ機能を適用します。以下のコードをSvelteコンポーネントに追加します。

<script>
  import { autosize } from './actions/autosize';
</script>

<textarea use:autosize></textarea>
<textarea use:autosize></textarea>
<textarea use:autosize></textarea>

これにより、Svelteではシンプルかつ効率的にTextareaの自動リサイズ機能を実装することができます。

まとめ

Svelteのuseディレクティブを利用することで、Textareaの自動リサイズ機能を非常にシンプルに実装することができました。

Reactではrefの管理の手間が発生するのに対し、Svelteでは仮想DOMを経由しないので、より簡潔に機能を追加することができます。

Discussion