🗒️

react-hook-quillの紹介

2025/03/11に公開

はじめに

react-hook-quillというQuillの軽量ラッパーを開発したので紹介します。
QuillはSlabが開発をしているリッチテキストエディタです。QuillはReactなどのライブラリの上に構築されておらず、TypeScriptで開発されており、Reactで使うためにはReact用の実装を追加する必要があります。

すでにいくつかのReactとQuillの連携用のライブラリはありますが、Quillの提供するAPIが連携用のライブラリ側でふさがれていることがある等、ユースケースによっては課題が生じそうなものがあったため、新たに開発を行いました。

下記はreact-hook-quillの利用例です。

import { memo, useRef } from 'react';
import 'quill/dist/quill.snow.css';
import { Delta } from 'quill';
import { useQuill, usePersistentDelta } from 'react-hook-quill';

const Editor = memo(() => {
  const ref = useRef<HTMLDivElement>(null);
  const { persistentDeltaSetting } = usePersistentDelta(
    {
      containerRef: ref,
      options: {
        theme: 'snow'
      }
    },
    new Delta().insert('Hello Quill')
  );

  // Quillのセットアップ
  useQuill({ setting: persistentDeltaSetting });

  return (
    <div ref={ref} />
  );
});

react-hook-quillの設計について

useEffectの使用

react-hook-quillではuseQuill内のuseEffectでQuillの初期化とクリーンアップを行っています。useEffectを使用しなくてよいケースは多々ありますが、今回はQuillを外部のシステムとして扱い、useEffectを使用する方法がフィットしました。

ただし、カスタムフックでuseEffectを隠ぺいしてしまうと、利用者側がuseEffectが使用されていることを認識しづらい課題が生じます。この課題に関してはドキュメントに明記するという方法を取っています。

ユーザー編集の課題

useQuillではアンマウントと再レンダー時にクリーンアップ処理が走るため、例えばQuillで編集中に親コンポーネントが再レンダーされると、編集内容も初期化されます。
処理の整合性を保つためには正しい挙動ですが、Quillで編集するユーザーからすると編集中の内容が初期化されることは意図しない挙動になります。
この課題に対応するためreact-hook-quillではusePersistentDeltauesSyncDeltaという2つのカスタムフックを用意しています。

usePersistentDeltaを利用すると、React側ではユーザーの編集を関知せずに、なおかつコンポーネントの再レンダー時には編集内容を維持します。内部的にはクリーンアップ時に編集内容を一時的に退避し、次の初期化時にセットし直します。

usePersistentDeltaの利用時はReact側ではユーザーの編集を関知しないため、編集のたびに再レンダーが走ることも起きません。
例えば保存時にいままでの編集内容を使用したいだけの場合、編集内容をReact側のステートとして持つ必要はありません。
仮に上記のユースケースであえて編集内容をReat側のステートとして管理する場合は編集のたびに再レンダーが発生するためオーバーヘッドになります。

また、コンポーネント側でステートを持ちたい場合のためにuseSyncDeltaも用意しています。

react-hook-quillでは上記2つのカスタムフックはあくまでオプションとして用意しているため、Quillの初期化とクリーンアップが責務のuseQuillのみを使用し、それ以外は自前で実装もできます。責務ごとにカスタムフックを分けて組み合わせられるようにすることで、異なるユースケースに応じて柔軟に対応できる設計を目指しています。

まとめ

react-hook-quillの外観をまとめると下記のようになります。
overview

react-hook-quillによってより柔軟にQuillをReactに組み込み、Quillを最大限活用できるケースが増えればと思っています。

Discussion