React Hook Form と Draft.js の組み合わせ

React Hook Form を使えばフォーム周りの state を一元管理したり、バリデーションを加えたり拡張できるけれど、Draft.js の値も組み込めるのか、というのが気になるところだと思う。

「React Hook Form で、Draft.js の state を管理したい」「React Hook Form と Draft.js を組み合わせたい」など、お困りなら力になれるかもしれない。

はじめに

リッチテキストエディタを単一に配置する程度ならば、個別に state を設けるのみで済まされる。これは Draft.js 公式のドキュメントに掲載されているように、ひとつの <Editor> に対して、ひとつの editorState を設定するというものだ。

だけど実際には、リッチテキストエディタもフォームの一部であることが自然で、そこには入力フィールドがあったり、選択フィールドがあったり、チェックボックスがあったりすることだろう。

そうするとフォームヘルパー系のライブラリ(react-hook-form)によるフォーム管理が見込めるわけで、そんななか Draft.js の <Editor> だけ別途 state を定義しているのは残念に思えてくる。

どうかこれも一緒に管理できないものか、というのがこのエントリーの根幹になっている。興味を引く内容であったならば引き続きお付き合いいただきたい。

React Hook Form と Draft.js を組み合わせよう

React Hook Form と Draft.js の組み合わせにおける最小構成を用意させてもらった。

実装環境

各種関連パッケージのバージョンは、以下コードを確認してほしい。

"dependencies": {
 "draft-js": "^0.11.7",
 "react": "^17.0.2",
 "react-dom": "^17.0.2",
 "react-hook-form": "^7.20.5"
 ...
},

コンポーネント

React コンポーネントは、以下コードを確認してほしい。

import { useState } from 'react';
import { useForm, useController } from 'react-hook-form';
import { Editor, EditorState, convertToRaw } from 'draft-js';

function App() {
 const [raw, setRaw] = useState();
 const { handleSubmit, control } = useForm();

 const {
   field: { onChange, value },
} = useController({
   name: 'richEditor',
   control,
   rules: { required: true },
   defaultValue: EditorState.createEmpty(),
});

 const submit = ({ richEditor }) => {
   const convertToRawData = convertToRaw(richEditor.getCurrentContent());
   setRaw(convertToRawData);
};

 return (
   <form onSubmit={handleSubmit(submit)}>
     <Editor editorState={value} onChange={onChange} />
     <button type="submit">送信</button>
     <pre>{JSON.stringify(raw, null, 2)}</pre>
   </form>
);
}

export default App;

リッチテキストエディタと submit ボタンだけのシンプルな構成のもので、submit すれば、下部に文字列化した JSONデータが表示される。

入力したデータを視覚してほしかったから、<pre>{JSON.stringify(raw, null, 2)}</pre> を含めているけれど、本来ならば submit 関数で処理が完了するから、そもそも const [raw, setRaw] = useState(); の定義がいらない。

useForm が発行した controluseController に渡すことで onChangevalue が用意される。これを <Editor> の props に流し込めば、リッチテキストエディタも React Hook Form 経由で入力値を参照できるようになる。

もしリッチテキストエディタを複数配置することになったならば、それにともない配置数と同数の useController の実行が求められる。そのようなときはリッチテキストエディタと useController を切り出して、コンポーネントにしてしまえばいい。

まとめ

以上、React Hook Form と Draft.js の組み合わせ方に関する共有だった。

実装環境の項目に示したとおりに各種パッケージのバージョンを合わせてもらえば再現できると信じている。ただし React Hook Form のバージョンが 7 未満だった場合は、useController ではなく、<Controller> を用いなければならないことに注意してほしい。

リッチテキストエディタ自体を設置する要件というのは、それほど多いわけではない。けれども、いざ実装しようということになると、フォーム周りの装いに合わせたいと感じてしまうものだ。

このエントリーが、あなたのクリエイティビティを刺激するものであると期待したい。

コメントを残す

メールアドレスが公開されることはありません。*がついている欄は必須項目です。

日本語が含まれない投稿は無視されますのでご注意ください。