Draft.jsのアンドゥ/リドゥ機能を完全掌握:テキストエディター体験を向上させるガイド

Draft.jsのアンドゥ/リドゥ機能を完全掌握:テキストエディター体験を向上させるガイド

Draft.jsはFacebookが開発したReactベースのテキスト編集フレームワークであり、強力なリッチテキスト編集機能を提供します。Reactフレームワークとしてのその核心的な利点は、エディターの状態をReactの状態管理システムに完全に組み込むことにあります。その中でも、アンドゥ/リドゥ(元に戻す/やり直し)機能はユーザーの編集体験を保障するための重要な機能です。本記事では、Draft.jsのアンドゥ/リドゥ実装の原理を深く解析し、開発者がこの核心機能を迅速に習得できるよう支援します。

アンドゥ/リドゥの基本原理

Draft.jsのアンドゥ/リドゥ機能は、エディターの最上位状態オブジェクトであるEditorStateの上に構築されています。内部では、2つの重要なスタック構造が維持されています:

  • undoStack:アンドゥ可能な履歴状態を格納
  • redoStack:リドゥ可能な履歴状態を格納

ユーザーが編集操作を実行すると、現在のContentStateがアンドゥスタックにプッシュされます。アンドゥ操作を実行すると、現在の状態はリドゥスタックにプッシュされ、同時にアンドゥスタックから最近の履歴状態がポップされて復元されます。リドゥ操作の場合はその逆です。

基本的なAPI使用方法

1. アンドゥ/リドゥ対応エディターの作成

アンドゥ/リドゥ機能を有効にするには、デフォルト設定でエディターを作成するだけで十分です。なぜならallowUndoプロパティのデフォルト値はtrueだからです:

import { Editor, EditorState } from 'draft-js';

class RichTextEditor extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      editorState: EditorState.createEmpty()
    };
  }
  
  // ...
}

2. アンドゥ操作の実行

EditorState.undo()静的メソッドを使用してアンドゥを実行します:

const performUndo = () => {
  this.setState({
    editorState: EditorState.undo(this.state.editorState)
  });
};

3. リドゥ操作の実行

EditorState.redo()静的メソッドを使用してリドゥを実行します:

const performRedo = () => {
  this.setState({
    editorState: EditorState.redo(this.state.editorState)
  });
};

高度な応用テクニック

カスタムアンドゥ/リドゥショートカットキー

Draft.jsはデフォルトでCtrl+Z(Windows/Linux)とCmd+Z(Mac)によるアンドゥ、Ctrl+Shift+ZまたはCmd+Shift+Zによるリドゥをサポートしています。カスタムキーバインディングを設定することで、この動作を変更できます:

import { getDefaultKeyBinding, KeyBindingUtil } from 'draft-js';

const { hasCommandModifier } = KeyBindingUtil;

function customKeyBindingFn(e) {
  // Alt+Zをアンドゥに割り当て
  if (e.altKey && e.key === 'z' && !e.shiftKey) {
    return 'undo';
  }
  
  // Alt+Shift+Zをリドゥに割り当て
  if (e.altKey && e.key === 'z' && e.shiftKey) {
    return 'redo';
  }
  
  return getDefaultKeyBinding(e);
}

アンドゥ/リドゥ機能の無効化

エディターでアンドゥ/リドゥ機能が必要ない場合は、allowUndofalseに設定して無効化できます。これによりメモリ使用量を削減できます:

const editorStateWithoutHistory = EditorState.set(editorState, {
  allowUndo: false
});

アンドゥ/リドゥイベントの監視

エディターのonChangeコールバックを使用して、アンドゥ/リドゥ操作を検出できます:

const handleEditorChange = (editorState) => {
  const lastOperationType = editorState.getLastChangeType();
  
  if (lastOperationType === 'undo') {
    console.log('ユーザーがアンドゥ操作を実行しました');
  } else if (lastOperationType === 'redo') {
    console.log('ユーザーがリドゥ操作を実行しました');
  }
  
  this.setState({ editorState });
};

実装原理の深層解析

Draft.jsのアンドゥ/リドゥメカニズムは、主に以下の核心モジュールの連携によって実現されています:

  1. EditorStateクラスundo()redo()静的メソッドを提供し、状態スタックを管理
  2. ContentStateクラス:エディターの内容状態を格納し、スタックの基本要素となる
  3. keyCommandUndo.js:アンドゥコマンドの具体的な実装を処理

実装の核心はsrc/component/handlers/edit/commands/keyCommandUndo.jsにあり、現在の状態をリドゥスタックにプッシュし、アンドゥスタックから履歴状態を復元する役割を担っています:

function handleUndoCommand(editorState, update) {
  const nextState = EditorState.undo(editorState);
  if (nextState !== editorState) {
    update(nextState);
    return 'handled';
  }
  return 'not-handled';
}

一方、src/component/handlers/edit/editOnKeyDown.jsでは、アンドゥショートカットキーの監視が登録されています:

case 'undo':
  return handleUndoCommand(editorState, editor.update);

パフォーマンス最適化の提案

  • 履歴記録の長さを適切に制御:Draft.jsにはスタック深度を直接制限するAPIはありませんが、カスタムロジックを用いて定期的に履歴をクリーンアップできます
  • 不変データ構造の活用:Draft.jsはImmutable.jsを基盤として構築されており、状態変更の効率性を確保しています
  • 不必要な状態記録の回避:カスタムchangeTypeを用いて、どの操作が履歴スタックに記録されるべきかを制御できます

まとめ

アンドゥ/リドゥ機能は現代のテキストエディターに不可欠な特性であり、Draft.jsは優雅なダブルスタック設計とImmutableデータ構造を通じて、効率的で信頼性の高い実装を提供しています。本記事で紹介したAPI使用方法や高度なテクニックを習得することで、ユーザーの期待に応えるアンドゥ/リドゥ体験を簡単に実装し、リッチテキストエディターの専門性と使いやすさを向上させることができます。

詳細情報については公式ドキュメント:docs/APIReference-EditorState.mdを参照してください。そこではEditorStateのすべてのメソッドとプロパティが詳細に説明されています。

タグ: Draft.js React テキストエディター アンドゥ/リドゥ 状態管理

5月17日 09:06 投稿